blob: adac45bdc9df826959c2e216013561ee00227f46 [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*,
senorblanco5e5f9482014-08-26 12:27:12 -0700283 const CropRect*, uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700284
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000285 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000286 SkScalar kd() const { return fKD; }
287
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000288protected:
reed9fa60da2014-08-21 07:59:51 -0700289 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700290 SkScalar kd, SkImageFilter* input, const CropRect* cropRect,
291 uint32_t uniqueID);
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000292 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000293 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000294 SkBitmap* result, SkIPoint* offset) const SK_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&,
297 const SkIRect& bounds) const SK_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,
joshualittb0a8a372014-09-23 09:50:21 -0700309 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*,
310 uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700311
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,
senorblanco5e5f9482014-08-26 12:27:12 -0700319 SkScalar shininess, SkImageFilter* input, const CropRect*,
320 uint32_t uniqueID);
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000321 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000322 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000323 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000324#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700325 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
326 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000327#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000328
329private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000330 SkScalar fKS;
331 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700332 friend class SkLightingImageFilter;
333 typedef SkLightingImageFilter INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000334};
335
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000336#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000337
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000338class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000339public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000340 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000341 virtual ~GrLightingEffect();
342
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000343 const SkLight* light() const { return fLight; }
344 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000345 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000346
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000347protected:
bsalomon0e08fc12014-10-15 08:19:04 -0700348 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000349
egdaniel605dd0f2014-11-12 08:35:25 -0800350 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700351 // lighting shaders are complicated. We just throw up our hands.
egdanielccb2e382014-10-13 12:53:46 -0700352 inout->mulByUnknownColor();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700353 }
354
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000355private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000356 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000357 const SkLight* fLight;
358 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000359 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000360};
361
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000362class GrDiffuseLightingEffect : public GrLightingEffect {
363public:
joshualittb0a8a372014-09-23 09:50:21 -0700364 static GrFragmentProcessor* Create(GrTexture* texture,
365 const SkLight* light,
366 SkScalar surfaceScale,
367 const SkMatrix& matrix,
368 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700369 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
370 light,
371 surfaceScale,
372 matrix,
373 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000374 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000375
joshualitteb2a6762014-12-04 11:35:33 -0800376 virtual const char* name() const SK_OVERRIDE { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000377
joshualitteb2a6762014-12-04 11:35:33 -0800378 virtual void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000379
joshualitteb2a6762014-12-04 11:35:33 -0800380 virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE;
381
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000382 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000383
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000384private:
bsalomon0e08fc12014-10-15 08:19:04 -0700385 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000386
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000387 GrDiffuseLightingEffect(GrTexture* texture,
388 const SkLight* light,
389 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000390 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000391 SkScalar kd);
392
joshualittb0a8a372014-09-23 09:50:21 -0700393 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000394 typedef GrLightingEffect INHERITED;
395 SkScalar fKD;
396};
397
398class GrSpecularLightingEffect : public GrLightingEffect {
399public:
joshualittb0a8a372014-09-23 09:50:21 -0700400 static GrFragmentProcessor* Create(GrTexture* texture,
401 const SkLight* light,
402 SkScalar surfaceScale,
403 const SkMatrix& matrix,
404 SkScalar ks,
405 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700406 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
407 light,
408 surfaceScale,
409 matrix,
410 ks,
411 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000412 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000413
joshualitteb2a6762014-12-04 11:35:33 -0800414 virtual const char* name() const SK_OVERRIDE { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000415
joshualitteb2a6762014-12-04 11:35:33 -0800416 virtual void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const SK_OVERRIDE;
417
418 virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE;
419
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000420 SkScalar ks() const { return fKS; }
421 SkScalar shininess() const { return fShininess; }
422
423private:
bsalomon0e08fc12014-10-15 08:19:04 -0700424 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000425
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000426 GrSpecularLightingEffect(GrTexture* texture,
427 const SkLight* light,
428 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000429 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000430 SkScalar ks,
431 SkScalar shininess);
432
joshualittb0a8a372014-09-23 09:50:21 -0700433 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000434 typedef GrLightingEffect INHERITED;
435 SkScalar fKS;
436 SkScalar fShininess;
437};
438
439///////////////////////////////////////////////////////////////////////////////
440
441class GrGLLight {
442public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000443 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000444
445 /**
446 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
447 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
448 */
joshualitt15988992014-10-09 15:04:05 -0700449 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000450
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000451 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000452 * These two functions are called from GrGLLightingEffect's emitCode() function.
453 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
454 * the light. The expression will be used in the FS. emitLightColor writes an expression into
455 * the FS that is the color of the light. Either function may add functions and/or uniforms to
456 * the FS. The default of emitLightColor appends the name of the constant light color uniform
457 * and so this function only needs to be overridden if the light color varies spatially.
458 */
joshualitt15988992014-10-09 15:04:05 -0700459 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
460 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000461
462 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
463 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700464 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000465 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000466
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000467protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000468 /**
469 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
470 * function.
471 */
472 UniformHandle lightColorUni() const { return fColorUni; }
473
474private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000475 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000476
477 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000478};
479
480///////////////////////////////////////////////////////////////////////////////
481
482class GrGLDistantLight : public GrGLLight {
483public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000484 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700485 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000486 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700487 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000488
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000489private:
490 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000491 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492};
493
494///////////////////////////////////////////////////////////////////////////////
495
496class GrGLPointLight : public GrGLLight {
497public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000498 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700499 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000500 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700501 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000502
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000503private:
504 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000505 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506};
507
508///////////////////////////////////////////////////////////////////////////////
509
510class GrGLSpotLight : public GrGLLight {
511public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000512 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700513 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000514 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700515 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
516 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000517
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518private:
519 typedef GrGLLight INHERITED;
520
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000521 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000522 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000523 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000524 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000525 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000526 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000527 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000528};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000529#else
530
531class GrGLLight;
532
533#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534
535};
536
537///////////////////////////////////////////////////////////////////////////////
538
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000539class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000540public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000541 SK_DECLARE_INST_COUNT(SkLight)
542
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000543 enum LightType {
544 kDistant_LightType,
545 kPoint_LightType,
546 kSpot_LightType,
547 };
548 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000549 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000550 virtual GrGLLight* createGLLight() const = 0;
551 virtual bool isEqual(const SkLight& other) const {
552 return fColor == other.fColor;
553 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000554 // Called to know whether the generated GrGLLight will require access to the fragment position.
555 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000556 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000557
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000558 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000559 void flattenLight(SkWriteBuffer& buffer) const;
560 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000561
djsollen@google.com08337772012-06-26 14:33:13 +0000562protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000563 SkLight(SkColor color)
564 : fColor(SkIntToScalar(SkColorGetR(color)),
565 SkIntToScalar(SkColorGetG(color)),
566 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000567 SkLight(const SkPoint3& color)
568 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000569 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000570 fColor = readPoint3(buffer);
571 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000572
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000573 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000574
djsollen@google.com08337772012-06-26 14:33:13 +0000575
576private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000577 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000578 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000579};
580
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000581///////////////////////////////////////////////////////////////////////////////
582
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000583class SkDistantLight : public SkLight {
584public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000585 SkDistantLight(const SkPoint3& direction, SkColor color)
586 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587 }
djsollen@google.com08337772012-06-26 14:33:13 +0000588
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
590 return fDirection;
591 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000592 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000593 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000594 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000595 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
596#if SK_SUPPORT_GPU
597 return SkNEW(GrGLDistantLight);
598#else
599 SkDEBUGFAIL("Should not call in GPU-less build");
600 return NULL;
601#endif
602 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000603 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
604
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000605 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
606 if (other.type() != kDistant_LightType) {
607 return false;
608 }
609
610 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
611 return INHERITED::isEqual(other) &&
612 fDirection == o.fDirection;
613 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000614
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000615 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000616 fDirection = readPoint3(buffer);
617 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618
djsollen@google.com08337772012-06-26 14:33:13 +0000619protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000620 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
621 : INHERITED(color), fDirection(direction) {
622 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000623 virtual SkLight* transform(const SkMatrix& matrix) const {
624 return new SkDistantLight(direction(), color());
625 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000626 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000627 writePoint3(fDirection, buffer);
628 }
629
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000630private:
djsollen@google.com08337772012-06-26 14:33:13 +0000631 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000632 SkPoint3 fDirection;
633};
634
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000635///////////////////////////////////////////////////////////////////////////////
636
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000637class SkPointLight : public SkLight {
638public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000639 SkPointLight(const SkPoint3& location, SkColor color)
640 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000641
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000642 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
643 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
644 fLocation.fY - SkIntToScalar(y),
645 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
646 direction.normalize();
647 return direction;
648 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000649 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000650 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000651 const SkPoint3& location() const { return fLocation; }
652 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000653#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000654 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000655#else
656 SkDEBUGFAIL("Should not call in GPU-less build");
657 return NULL;
658#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000659 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000660 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000661 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662 if (other.type() != kPoint_LightType) {
663 return false;
664 }
665 const SkPointLight& o = static_cast<const SkPointLight&>(other);
666 return INHERITED::isEqual(other) &&
667 fLocation == o.fLocation;
668 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000669 virtual SkLight* transform(const SkMatrix& matrix) const {
670 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
671 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000672 // Use X scale and Y scale on Z and average the result
673 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
674 matrix.mapVectors(&locationZ, 1);
675 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000676 return new SkPointLight(location, color());
677 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000678
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000679 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000680 fLocation = readPoint3(buffer);
681 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000682
683protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000684 SkPointLight(const SkPoint3& location, const SkPoint3& color)
685 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000686 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000687 writePoint3(fLocation, buffer);
688 }
689
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000690private:
djsollen@google.com08337772012-06-26 14:33:13 +0000691 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000692 SkPoint3 fLocation;
693};
694
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000695///////////////////////////////////////////////////////////////////////////////
696
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000697class SkSpotLight : public SkLight {
698public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000699 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
700 : INHERITED(color),
701 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000702 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000703 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704 {
705 fS = target - location;
706 fS.normalize();
707 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000708 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000709 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
710 fConeScale = SkScalarInvert(antiAliasThreshold);
711 }
djsollen@google.com08337772012-06-26 14:33:13 +0000712
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000713 virtual SkLight* transform(const SkMatrix& matrix) const {
714 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
715 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000716 // Use X scale and Y scale on Z and average the result
717 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
718 matrix.mapVectors(&locationZ, 1);
719 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000720 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
721 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000722 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
723 matrix.mapVectors(&targetZ, 1);
724 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
725 SkPoint3 s = target - location;
726 s.normalize();
727 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000728 }
729
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000730 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
731 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
732 fLocation.fY - SkIntToScalar(y),
733 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
734 direction.normalize();
735 return direction;
736 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000737 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738 SkScalar cosAngle = -surfaceToLight.dot(fS);
739 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000740 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000741 }
742 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
743 if (cosAngle < fCosInnerConeAngle) {
744 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000745 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000746 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000747 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000748 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000749 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000750#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000751 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000752#else
753 SkDEBUGFAIL("Should not call in GPU-less build");
754 return NULL;
755#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000756 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000757 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000758 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000759 const SkPoint3& location() const { return fLocation; }
760 const SkPoint3& target() const { return fTarget; }
761 SkScalar specularExponent() const { return fSpecularExponent; }
762 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
763 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
764 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000765 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000766
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000767 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000768 fLocation = readPoint3(buffer);
769 fTarget = readPoint3(buffer);
770 fSpecularExponent = buffer.readScalar();
771 fCosOuterConeAngle = buffer.readScalar();
772 fCosInnerConeAngle = buffer.readScalar();
773 fConeScale = buffer.readScalar();
774 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000775 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
776 SkScalarIsFinite(fCosOuterConeAngle) &&
777 SkScalarIsFinite(fCosInnerConeAngle) &&
778 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000779 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000780protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000781 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
782 : INHERITED(color),
783 fLocation(location),
784 fTarget(target),
785 fSpecularExponent(specularExponent),
786 fCosOuterConeAngle(cosOuterConeAngle),
787 fCosInnerConeAngle(cosInnerConeAngle),
788 fConeScale(coneScale),
789 fS(s)
790 {
791 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000792 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000793 writePoint3(fLocation, buffer);
794 writePoint3(fTarget, buffer);
795 buffer.writeScalar(fSpecularExponent);
796 buffer.writeScalar(fCosOuterConeAngle);
797 buffer.writeScalar(fCosInnerConeAngle);
798 buffer.writeScalar(fConeScale);
799 writePoint3(fS, buffer);
800 }
801
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000802 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000803 if (other.type() != kSpot_LightType) {
804 return false;
805 }
806
807 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
808 return INHERITED::isEqual(other) &&
809 fLocation == o.fLocation &&
810 fTarget == o.fTarget &&
811 fSpecularExponent == o.fSpecularExponent &&
812 fCosOuterConeAngle == o.fCosOuterConeAngle;
813 }
814
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000815private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000816 static const SkScalar kSpecularExponentMin;
817 static const SkScalar kSpecularExponentMax;
818
djsollen@google.com08337772012-06-26 14:33:13 +0000819 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000820 SkPoint3 fLocation;
821 SkPoint3 fTarget;
822 SkScalar fSpecularExponent;
823 SkScalar fCosOuterConeAngle;
824 SkScalar fCosInnerConeAngle;
825 SkScalar fConeScale;
826 SkPoint3 fS;
827};
828
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000829// According to the spec, the specular term should be in the range [1, 128] :
830// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000831const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
832const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000833
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000834///////////////////////////////////////////////////////////////////////////////
835
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000836void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000837 // Write type first, then baseclass, then subclass.
838 buffer.writeInt(this->type());
839 writePoint3(fColor, buffer);
840 this->onFlattenLight(buffer);
841}
842
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000843/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000844 // Read type first.
845 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
846 switch (type) {
847 // Each of these constructors must first call SkLight's, so we'll read the baseclass
848 // then subclass, same order as flattenLight.
849 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
850 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
851 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
852 default:
853 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000854 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000855 return NULL;
856 }
857}
858///////////////////////////////////////////////////////////////////////////////
859
senorblanco9ea3d572014-07-08 09:16:22 -0700860SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700861 SkImageFilter* input, const CropRect* cropRect,
862 uint32_t uniqueID)
863 : INHERITED(1, &input, cropRect, uniqueID)
reed9fa60da2014-08-21 07:59:51 -0700864 , fLight(SkRef(light))
865 , fSurfaceScale(surfaceScale / 255)
866{}
867
868SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
869 SkColor lightColor,
870 SkScalar surfaceScale,
871 SkScalar kd,
872 SkImageFilter* input,
873 const CropRect* cropRect) {
874 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
875 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000876}
877
reed9fa60da2014-08-21 07:59:51 -0700878SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
879 SkColor lightColor,
880 SkScalar surfaceScale,
881 SkScalar kd,
882 SkImageFilter* input,
883 const CropRect* cropRect) {
884 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
885 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000886}
887
reed9fa60da2014-08-21 07:59:51 -0700888SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
889 const SkPoint3& target,
890 SkScalar specularExponent,
891 SkScalar cutoffAngle,
892 SkColor lightColor,
893 SkScalar surfaceScale,
894 SkScalar kd,
895 SkImageFilter* input,
896 const CropRect* cropRect) {
897 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
898 cutoffAngle, lightColor)));
899 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000900}
901
reed9fa60da2014-08-21 07:59:51 -0700902SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
903 SkColor lightColor,
904 SkScalar surfaceScale,
905 SkScalar ks,
906 SkScalar shine,
907 SkImageFilter* input,
908 const CropRect* cropRect) {
909 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
910 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911}
912
reed9fa60da2014-08-21 07:59:51 -0700913SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
914 SkColor lightColor,
915 SkScalar surfaceScale,
916 SkScalar ks,
917 SkScalar shine,
918 SkImageFilter* input,
919 const CropRect* cropRect) {
920 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
921 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000922}
923
reed9fa60da2014-08-21 07:59:51 -0700924SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
925 const SkPoint3& target,
926 SkScalar specularExponent,
927 SkScalar cutoffAngle,
928 SkColor lightColor,
929 SkScalar surfaceScale,
930 SkScalar ks,
931 SkScalar shine,
932 SkImageFilter* input,
933 const CropRect* cropRect) {
934 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
935 cutoffAngle, lightColor)));
936 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000937}
938
reed9fa60da2014-08-21 07:59:51 -0700939SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000940
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000941void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000942 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000943 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700944 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000945}
946
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000947///////////////////////////////////////////////////////////////////////////////
948
reed9fa60da2014-08-21 07:59:51 -0700949SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700950 SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -0700951 if (NULL == light) {
952 return NULL;
953 }
954 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
955 return NULL;
956 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000957 // According to the spec, kd can be any non-negative number :
958 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700959 if (kd < 0) {
960 return NULL;
961 }
senorblanco5e5f9482014-08-26 12:27:12 -0700962 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -0700963}
964
senorblanco5e5f9482014-08-26 12:27:12 -0700965SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
966 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -0700967 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000968{
969}
970
reed9fa60da2014-08-21 07:59:51 -0700971SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
972 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
973 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
974 SkScalar surfaceScale = buffer.readScalar();
975 SkScalar kd = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -0700976 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -0700977}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000978
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000979void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980 this->INHERITED::flatten(buffer);
981 buffer.writeScalar(fKD);
982}
983
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000984bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
985 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000986 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000987 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000988 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000989 SkImageFilter* input = getInput(0);
990 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000991 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000992 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000993 return false;
994 }
995
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000996 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000997 return false;
998 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000999 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001000 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001001 return false;
1002 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001003
1004 if (bounds.width() < 2 || bounds.height() < 2) {
1005 return false;
1006 }
1007
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001008 SkAutoLockPixels alp(src);
1009 if (!src.getPixels()) {
1010 return false;
1011 }
1012
reed84825042014-09-02 12:50:45 -07001013 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001014 return false;
1015 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001016
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001017 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001018
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001019 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001020 offset->fX = bounds.left();
1021 offset->fY = bounds.top();
1022 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001023 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001024 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001025 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001026 break;
1027 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001028 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001029 break;
1030 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001031 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001032 break;
1033 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001034
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001035 return true;
1036}
1037
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001038#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001039bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1040 GrTexture* texture,
1041 const SkMatrix& matrix,
1042 const SkIRect&) const {
1043 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001044 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001045 *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001046 }
1047 return true;
1048}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001049#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001050
1051///////////////////////////////////////////////////////////////////////////////
1052
reed9fa60da2014-08-21 07:59:51 -07001053SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -07001054 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -07001055 if (NULL == light) {
1056 return NULL;
1057 }
1058 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1059 return NULL;
1060 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001061 // According to the spec, ks can be any non-negative number :
1062 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001063 if (ks < 0) {
1064 return NULL;
1065 }
1066 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco5e5f9482014-08-26 12:27:12 -07001067 (light, surfaceScale, ks, shininess, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -07001068}
1069
senorblanco5e5f9482014-08-26 12:27:12 -07001070SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
1071 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -07001072 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001073 fShininess(shininess)
1074{
1075}
1076
reed9fa60da2014-08-21 07:59:51 -07001077SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1078 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1079 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1080 SkScalar surfaceScale = buffer.readScalar();
1081 SkScalar ks = buffer.readScalar();
1082 SkScalar shine = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -07001083 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -07001084}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001085
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001086void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001087 this->INHERITED::flatten(buffer);
1088 buffer.writeScalar(fKS);
1089 buffer.writeScalar(fShininess);
1090}
1091
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001092bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1093 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001094 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001095 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001096 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001097 SkImageFilter* input = getInput(0);
1098 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001099 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001100 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001101 return false;
1102 }
1103
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001104 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001105 return false;
1106 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001107
1108 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001109 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001110 return false;
1111 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001112
1113 if (bounds.width() < 2 || bounds.height() < 2) {
1114 return false;
1115 }
1116
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001117 SkAutoLockPixels alp(src);
1118 if (!src.getPixels()) {
1119 return false;
1120 }
1121
reed84825042014-09-02 12:50:45 -07001122 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001123 return false;
1124 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001125
1126 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001127 offset->fX = bounds.left();
1128 offset->fY = bounds.top();
1129 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001130 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001131 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001132 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001133 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001134 break;
1135 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001136 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001137 break;
1138 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001139 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001140 break;
1141 }
1142 return true;
1143}
1144
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001145#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001146bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1147 GrTexture* texture,
1148 const SkMatrix& matrix,
1149 const SkIRect&) const {
1150 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001151 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001152 *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001153 }
1154 return true;
1155}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001156#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001157
1158///////////////////////////////////////////////////////////////////////////////
1159
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001160#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001161
1162namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001163SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001164 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1165 SkScalarToFloat(random->nextSScalar1()),
1166 SkScalarToFloat(random->nextSScalar1()));
1167}
1168
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001169SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001170 int type = random->nextULessThan(3);
1171 switch (type) {
1172 case 0: {
1173 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1174 }
1175 case 1: {
1176 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1177 }
1178 case 2: {
1179 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1180 random_point3(random),
1181 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001182 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001183 random->nextU()));
1184 }
1185 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001186 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001187 return NULL;
1188 }
1189}
1190
1191}
1192
joshualittb0a8a372014-09-23 09:50:21 -07001193class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194public:
joshualitteb2a6762014-12-04 11:35:33 -08001195 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001196 virtual ~GrGLLightingEffect();
1197
joshualitt15988992014-10-09 15:04:05 -07001198 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -07001199 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001200 const char* outputColor,
1201 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001202 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001203 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001204
joshualittb0a8a372014-09-23 09:50:21 -07001205 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001206
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001207 /**
1208 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1209 */
joshualittb0a8a372014-09-23 09:50:21 -07001210 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001211
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001212protected:
joshualitt15988992014-10-09 15:04:05 -07001213 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001214
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001215private:
joshualittb0a8a372014-09-23 09:50:21 -07001216 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001217
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001218 UniformHandle fImageIncrementUni;
1219 UniformHandle fSurfaceScaleUni;
1220 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001221};
1222
1223///////////////////////////////////////////////////////////////////////////////
1224
1225class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1226public:
joshualitteb2a6762014-12-04 11:35:33 -08001227 GrGLDiffuseLightingEffect(const GrProcessor&);
joshualitt15988992014-10-09 15:04:05 -07001228 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001229 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001230
1231private:
1232 typedef GrGLLightingEffect INHERITED;
1233
bsalomon@google.com032b2212012-07-16 13:36:18 +00001234 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001235};
1236
1237///////////////////////////////////////////////////////////////////////////////
1238
1239class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1240public:
joshualitteb2a6762014-12-04 11:35:33 -08001241 GrGLSpecularLightingEffect(const GrProcessor&);
joshualitt15988992014-10-09 15:04:05 -07001242 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001243 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_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 fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001249 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001250};
1251
1252///////////////////////////////////////////////////////////////////////////////
1253
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001254GrLightingEffect::GrLightingEffect(GrTexture* texture,
1255 const SkLight* light,
1256 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001257 const SkMatrix& matrix)
bsalomon6267f812014-08-29 15:05:53 -07001258 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001259 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001260 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001261 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001262 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001263 if (light->requiresFragmentPosition()) {
1264 this->setWillReadFragmentPosition();
1265 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001266}
1267
1268GrLightingEffect::~GrLightingEffect() {
1269 fLight->unref();
1270}
1271
bsalomon0e08fc12014-10-15 08:19:04 -07001272bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001273 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001274 return fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001275 fSurfaceScale == s.fSurfaceScale;
1276}
1277
1278///////////////////////////////////////////////////////////////////////////////
1279
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001280GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1281 const SkLight* light,
1282 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001283 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001284 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001285 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001286 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001287}
1288
bsalomon0e08fc12014-10-15 08:19:04 -07001289bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001290 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001291 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001292 this->kd() == s.kd();
1293}
1294
joshualitteb2a6762014-12-04 11:35:33 -08001295void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1296 GrProcessorKeyBuilder* b) const {
1297 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1298}
1299
1300GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1301 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1302}
1303
joshualittb0a8a372014-09-23 09:50:21 -07001304GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001305
joshualittb0a8a372014-09-23 09:50:21 -07001306GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001307 GrContext* context,
1308 const GrDrawTargetCaps&,
1309 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001310 SkScalar surfaceScale = random->nextSScalar1();
1311 SkScalar kd = random->nextUScalar1();
1312 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001313 SkMatrix matrix;
1314 for (int i = 0; i < 9; i++) {
1315 matrix[i] = random->nextUScalar1();
1316 }
joshualittb0a8a372014-09-23 09:50:21 -07001317 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001318 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001319}
1320
1321
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001322///////////////////////////////////////////////////////////////////////////////
1323
joshualitteb2a6762014-12-04 11:35:33 -08001324GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001325 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001326 fLight = m.light()->createGLLight();
1327}
1328
1329GrGLLightingEffect::~GrGLLightingEffect() {
1330 delete fLight;
1331}
1332
joshualitt15988992014-10-09 15:04:05 -07001333void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001334 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001335 const char* outputColor,
1336 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001337 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001338 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001339 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001340 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001341 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001342 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001343 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001344 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001345 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001346 SkString lightFunc;
1347 this->emitLightFunc(builder, &lightFunc);
1348 static const GrGLShaderVar gSobelArgs[] = {
1349 GrGLShaderVar("a", kFloat_GrSLType),
1350 GrGLShaderVar("b", kFloat_GrSLType),
1351 GrGLShaderVar("c", kFloat_GrSLType),
1352 GrGLShaderVar("d", kFloat_GrSLType),
1353 GrGLShaderVar("e", kFloat_GrSLType),
1354 GrGLShaderVar("f", kFloat_GrSLType),
1355 GrGLShaderVar("scale", kFloat_GrSLType),
1356 };
1357 SkString sobelFuncName;
joshualitt15988992014-10-09 15:04:05 -07001358 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001359 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1360
1361 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001362 "sobel",
1363 SK_ARRAY_COUNT(gSobelArgs),
1364 gSobelArgs,
1365 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1366 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001367 static const GrGLShaderVar gPointToNormalArgs[] = {
1368 GrGLShaderVar("x", kFloat_GrSLType),
1369 GrGLShaderVar("y", kFloat_GrSLType),
1370 GrGLShaderVar("scale", kFloat_GrSLType),
1371 };
1372 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001373 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001374 "pointToNormal",
1375 SK_ARRAY_COUNT(gPointToNormalArgs),
1376 gPointToNormalArgs,
1377 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1378 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001379
1380 static const GrGLShaderVar gInteriorNormalArgs[] = {
1381 GrGLShaderVar("m", kFloat_GrSLType, 9),
1382 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1383 };
1384 SkString interiorNormalBody;
1385 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1386 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1387 "\t surfaceScale);\n",
1388 pointToNormalName.c_str(),
1389 sobelFuncName.c_str(),
1390 sobelFuncName.c_str());
1391 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001392 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001393 "interiorNormal",
1394 SK_ARRAY_COUNT(gInteriorNormalArgs),
1395 gInteriorNormalArgs,
1396 interiorNormalBody.c_str(),
1397 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001398
joshualitt30ba4362014-08-21 20:18:45 -07001399 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1400 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001401
1402 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1403 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1404
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001405 int index = 0;
1406 for (int dy = -1; dy <= 1; dy++) {
1407 for (int dx = -1; dx <= 1; dx++) {
1408 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001409 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001410 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1411 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1412 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001413 }
1414 }
joshualitt30ba4362014-08-21 20:18:45 -07001415 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001416 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001417 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001418 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001419 fsBuilder->codeAppend(";\n");
1420 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001421 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001422 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001423 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001424 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001425 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001426 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001427}
1428
joshualittb0a8a372014-09-23 09:50:21 -07001429void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1430 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
1431 b->add32(proc.cast<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001432}
1433
kkinnunen7510b222014-07-30 00:04:16 -07001434void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001435 const GrProcessor& proc) {
1436 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001437 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001438 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001439 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1440 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001441 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001442 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001443}
1444
1445///////////////////////////////////////////////////////////////////////////////
1446
1447///////////////////////////////////////////////////////////////////////////////
1448
joshualitteb2a6762014-12-04 11:35:33 -08001449GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1450 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001451}
1452
joshualitt15988992014-10-09 15:04:05 -07001453void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001454 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001455 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001456 kFloat_GrSLType, kDefault_GrSLPrecision,
1457 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001458
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001459 static const GrGLShaderVar gLightArgs[] = {
1460 GrGLShaderVar("normal", kVec3f_GrSLType),
1461 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1462 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1463 };
1464 SkString lightBody;
1465 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1466 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001467 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1468 "light",
1469 SK_ARRAY_COUNT(gLightArgs),
1470 gLightArgs,
1471 lightBody.c_str(),
1472 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001473}
1474
kkinnunen7510b222014-07-30 00:04:16 -07001475void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001476 const GrProcessor& proc) {
1477 INHERITED::setData(pdman, proc);
1478 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001479 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001480}
1481
1482///////////////////////////////////////////////////////////////////////////////
1483
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001484GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1485 const SkLight* light,
1486 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001487 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001488 SkScalar ks,
1489 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001490 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001491 fKS(ks),
1492 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001493 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001494}
1495
bsalomon0e08fc12014-10-15 08:19:04 -07001496bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001497 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001498 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001499 this->ks() == s.ks() &&
1500 this->shininess() == s.shininess();
1501}
1502
joshualitteb2a6762014-12-04 11:35:33 -08001503void GrSpecularLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1504 GrProcessorKeyBuilder* b) const {
1505 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1506}
1507
1508GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1509 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1510}
1511
joshualittb0a8a372014-09-23 09:50:21 -07001512GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001513
joshualittb0a8a372014-09-23 09:50:21 -07001514GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1515 GrContext* context,
1516 const GrDrawTargetCaps&,
1517 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001518 SkScalar surfaceScale = random->nextSScalar1();
1519 SkScalar ks = random->nextUScalar1();
1520 SkScalar shininess = random->nextUScalar1();
1521 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001522 SkMatrix matrix;
1523 for (int i = 0; i < 9; i++) {
1524 matrix[i] = random->nextUScalar1();
1525 }
joshualittb0a8a372014-09-23 09:50:21 -07001526 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001527 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001528}
1529
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001530///////////////////////////////////////////////////////////////////////////////
1531
joshualitteb2a6762014-12-04 11:35:33 -08001532GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1533 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001534}
1535
joshualitt15988992014-10-09 15:04:05 -07001536void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001537 const char* ks;
1538 const char* shininess;
1539
joshualitt30ba4362014-08-21 20:18:45 -07001540 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001541 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001542 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001543 kFloat_GrSLType, kDefault_GrSLPrecision, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001544
1545 static const GrGLShaderVar gLightArgs[] = {
1546 GrGLShaderVar("normal", kVec3f_GrSLType),
1547 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1548 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1549 };
1550 SkString lightBody;
1551 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1552 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001553 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1554 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001555 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1556 "light",
1557 SK_ARRAY_COUNT(gLightArgs),
1558 gLightArgs,
1559 lightBody.c_str(),
1560 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001561}
1562
kkinnunen7510b222014-07-30 00:04:16 -07001563void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001564 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001565 INHERITED::setData(pdman, effect);
1566 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001567 pdman.set1f(fKSUni, spec.ks());
1568 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001569}
1570
1571///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001572void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001573 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001574 kVec3f_GrSLType, kDefault_GrSLPrecision,
1575 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001576}
1577
joshualitt15988992014-10-09 15:04:05 -07001578void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001579 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001580 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001581}
1582
kkinnunen7510b222014-07-30 00:04:16 -07001583void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001584 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001585 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001586}
1587
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001588///////////////////////////////////////////////////////////////////////////////
1589
kkinnunen7510b222014-07-30 00:04:16 -07001590void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001591 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001592 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001593 SkASSERT(light->type() == SkLight::kDistant_LightType);
1594 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001595 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001596}
1597
joshualitt15988992014-10-09 15:04:05 -07001598void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001599 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001600 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1601 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001602 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001603 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001604}
1605
1606///////////////////////////////////////////////////////////////////////////////
1607
kkinnunen7510b222014-07-30 00:04:16 -07001608void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001609 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001610 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001611 SkASSERT(light->type() == SkLight::kPoint_LightType);
1612 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001613 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001614}
1615
joshualitt15988992014-10-09 15:04:05 -07001616void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001617 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001618 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1619 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001620 "LightLocation", &loc);
joshualitt15988992014-10-09 15:04:05 -07001621 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001622 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1623 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001624}
1625
1626///////////////////////////////////////////////////////////////////////////////
1627
kkinnunen7510b222014-07-30 00:04:16 -07001628void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001629 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001630 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001631 SkASSERT(light->type() == SkLight::kSpot_LightType);
1632 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001633 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1634 pdman.set1f(fExponentUni, spotLight->specularExponent());
1635 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1636 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1637 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1638 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001639}
1640
joshualitt15988992014-10-09 15:04:05 -07001641void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001642 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001643 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001644 kVec3f_GrSLType, kDefault_GrSLPrecision,
1645 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001646
joshualitt15988992014-10-09 15:04:05 -07001647 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001648 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1649 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001650}
1651
joshualitt15988992014-10-09 15:04:05 -07001652void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001653 const char *surfaceToLight) {
1654
1655 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1656
1657 const char* exponent;
1658 const char* cosInner;
1659 const char* cosOuter;
1660 const char* coneScale;
1661 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001662 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001663 kFloat_GrSLType, kDefault_GrSLPrecision,
1664 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001665 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001666 kFloat_GrSLType, kDefault_GrSLPrecision,
1667 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001668 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001669 kFloat_GrSLType, kDefault_GrSLPrecision,
1670 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001671 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001672 kFloat_GrSLType, kDefault_GrSLPrecision,
1673 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001674 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001675 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001676
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001677 static const GrGLShaderVar gLightColorArgs[] = {
1678 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1679 };
1680 SkString lightColorBody;
1681 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1682 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1683 lightColorBody.appendf("\t\treturn vec3(0);\n");
1684 lightColorBody.appendf("\t}\n");
1685 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1686 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1687 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1688 color, cosOuter, coneScale);
1689 lightColorBody.appendf("\t}\n");
1690 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt15988992014-10-09 15:04:05 -07001691 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001692 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001693 "lightColor",
1694 SK_ARRAY_COUNT(gLightColorArgs),
1695 gLightColorArgs,
1696 lightColorBody.c_str(),
1697 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001698
joshualitt30ba4362014-08-21 20:18:45 -07001699 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001700}
1701
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001702#endif
1703
djsollen@google.com08337772012-06-26 14:33:13 +00001704SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1705 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1706 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001707SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END