blob: b1271d8493194a8a1251a7c776cf5feb2b147314 [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
robertphillipsf3f5bad2014-12-19 13:49:15 -0800285 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000287 SkScalar kd() const { return fKD; }
288
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289protected:
reed9fa60da2014-08-21 07:59:51 -0700290 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700291 SkScalar kd, SkImageFilter* input, const CropRect* cropRect,
292 uint32_t uniqueID);
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000293 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000294 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000295 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000296#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700297 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
298 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000299#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000300
301private:
reed9fa60da2014-08-21 07:59:51 -0700302 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000303 typedef SkLightingImageFilter INHERITED;
304 SkScalar fKD;
305};
306
307class SkSpecularLightingImageFilter : public SkLightingImageFilter {
308public:
reed9fa60da2014-08-21 07:59:51 -0700309 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
joshualittb0a8a372014-09-23 09:50:21 -0700310 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*,
311 uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700312
robertphillipsf3f5bad2014-12-19 13:49:15 -0800313 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000314 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
315
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000316 SkScalar ks() const { return fKS; }
317 SkScalar shininess() const { return fShininess; }
318
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000319protected:
reed9fa60da2014-08-21 07:59:51 -0700320 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco5e5f9482014-08-26 12:27:12 -0700321 SkScalar shininess, SkImageFilter* input, const CropRect*,
322 uint32_t uniqueID);
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000323 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000324 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000325 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000326#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700327 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
328 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000329#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000330
331private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000332 SkScalar fKS;
333 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700334 friend class SkLightingImageFilter;
335 typedef SkLightingImageFilter INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000336};
337
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000338#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000339
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000340class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000341public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000342 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000343 virtual ~GrLightingEffect();
344
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000345 const SkLight* light() const { return fLight; }
346 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000347 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000348
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000349protected:
bsalomon0e08fc12014-10-15 08:19:04 -0700350 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000351
egdaniel605dd0f2014-11-12 08:35:25 -0800352 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700353 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800354 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700355 }
356
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000357private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000358 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000359 const SkLight* fLight;
360 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000361 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000362};
363
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000364class GrDiffuseLightingEffect : public GrLightingEffect {
365public:
joshualittb0a8a372014-09-23 09:50:21 -0700366 static GrFragmentProcessor* Create(GrTexture* texture,
367 const SkLight* light,
368 SkScalar surfaceScale,
369 const SkMatrix& matrix,
370 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700371 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
372 light,
373 surfaceScale,
374 matrix,
375 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000376 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000377
joshualitteb2a6762014-12-04 11:35:33 -0800378 virtual const char* name() const SK_OVERRIDE { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000379
joshualitteb2a6762014-12-04 11:35:33 -0800380 virtual void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000381
joshualitteb2a6762014-12-04 11:35:33 -0800382 virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE;
383
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000384 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000385
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000386private:
bsalomon0e08fc12014-10-15 08:19:04 -0700387 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000388
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000389 GrDiffuseLightingEffect(GrTexture* texture,
390 const SkLight* light,
391 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000392 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000393 SkScalar kd);
394
joshualittb0a8a372014-09-23 09:50:21 -0700395 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000396 typedef GrLightingEffect INHERITED;
397 SkScalar fKD;
398};
399
400class GrSpecularLightingEffect : public GrLightingEffect {
401public:
joshualittb0a8a372014-09-23 09:50:21 -0700402 static GrFragmentProcessor* Create(GrTexture* texture,
403 const SkLight* light,
404 SkScalar surfaceScale,
405 const SkMatrix& matrix,
406 SkScalar ks,
407 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700408 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
409 light,
410 surfaceScale,
411 matrix,
412 ks,
413 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000414 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000415
joshualitteb2a6762014-12-04 11:35:33 -0800416 virtual const char* name() const SK_OVERRIDE { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000417
joshualitteb2a6762014-12-04 11:35:33 -0800418 virtual void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const SK_OVERRIDE;
419
420 virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE;
421
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000422 SkScalar ks() const { return fKS; }
423 SkScalar shininess() const { return fShininess; }
424
425private:
bsalomon0e08fc12014-10-15 08:19:04 -0700426 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000427
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000428 GrSpecularLightingEffect(GrTexture* texture,
429 const SkLight* light,
430 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000431 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000432 SkScalar ks,
433 SkScalar shininess);
434
joshualittb0a8a372014-09-23 09:50:21 -0700435 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000436 typedef GrLightingEffect INHERITED;
437 SkScalar fKS;
438 SkScalar fShininess;
439};
440
441///////////////////////////////////////////////////////////////////////////////
442
443class GrGLLight {
444public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000445 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000446
447 /**
448 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
449 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
450 */
joshualitt15988992014-10-09 15:04:05 -0700451 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000452
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000453 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000454 * These two functions are called from GrGLLightingEffect's emitCode() function.
455 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
456 * the light. The expression will be used in the FS. emitLightColor writes an expression into
457 * the FS that is the color of the light. Either function may add functions and/or uniforms to
458 * the FS. The default of emitLightColor appends the name of the constant light color uniform
459 * and so this function only needs to be overridden if the light color varies spatially.
460 */
joshualitt15988992014-10-09 15:04:05 -0700461 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
462 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000463
464 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
465 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700466 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000467 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000468
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000469protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000470 /**
471 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
472 * function.
473 */
474 UniformHandle lightColorUni() const { return fColorUni; }
475
476private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000477 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000478
479 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000480};
481
482///////////////////////////////////////////////////////////////////////////////
483
484class GrGLDistantLight : public GrGLLight {
485public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000486 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700487 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000488 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700489 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000490
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491private:
492 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000493 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494};
495
496///////////////////////////////////////////////////////////////////////////////
497
498class GrGLPointLight : public GrGLLight {
499public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000500 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700501 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000502 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700503 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000504
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000505private:
506 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000507 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508};
509
510///////////////////////////////////////////////////////////////////////////////
511
512class GrGLSpotLight : public GrGLLight {
513public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000514 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700515 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000516 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700517 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
518 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000519
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000520private:
521 typedef GrGLLight INHERITED;
522
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000523 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000524 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000525 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000526 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000527 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000528 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000529 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000530};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000531#else
532
533class GrGLLight;
534
535#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536
537};
538
539///////////////////////////////////////////////////////////////////////////////
540
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000541class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000542public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000543 SK_DECLARE_INST_COUNT(SkLight)
544
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000545 enum LightType {
546 kDistant_LightType,
547 kPoint_LightType,
548 kSpot_LightType,
549 };
550 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000551 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000552 virtual GrGLLight* createGLLight() const = 0;
553 virtual bool isEqual(const SkLight& other) const {
554 return fColor == other.fColor;
555 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000556 // Called to know whether the generated GrGLLight will require access to the fragment position.
557 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000558 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000559
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000560 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000561 void flattenLight(SkWriteBuffer& buffer) const;
562 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000563
djsollen@google.com08337772012-06-26 14:33:13 +0000564protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000565 SkLight(SkColor color)
566 : fColor(SkIntToScalar(SkColorGetR(color)),
567 SkIntToScalar(SkColorGetG(color)),
568 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000569 SkLight(const SkPoint3& color)
570 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000571 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000572 fColor = readPoint3(buffer);
573 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000574
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000575 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000576
djsollen@google.com08337772012-06-26 14:33:13 +0000577
578private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000579 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000580 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000581};
582
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000583///////////////////////////////////////////////////////////////////////////////
584
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000585class SkDistantLight : public SkLight {
586public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000587 SkDistantLight(const SkPoint3& direction, SkColor color)
588 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589 }
djsollen@google.com08337772012-06-26 14:33:13 +0000590
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
592 return fDirection;
593 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000594 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
tfarina912ed6e2014-12-14 15:20:10 -0800595 virtual LightType type() const SK_OVERRIDE { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000596 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000597 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
598#if SK_SUPPORT_GPU
599 return SkNEW(GrGLDistantLight);
600#else
601 SkDEBUGFAIL("Should not call in GPU-less build");
602 return NULL;
603#endif
604 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000605 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
606
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000607 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
608 if (other.type() != kDistant_LightType) {
609 return false;
610 }
611
612 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
613 return INHERITED::isEqual(other) &&
614 fDirection == o.fDirection;
615 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000616
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000617 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000618 fDirection = readPoint3(buffer);
619 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000620
djsollen@google.com08337772012-06-26 14:33:13 +0000621protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000622 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
623 : INHERITED(color), fDirection(direction) {
624 }
tfarina912ed6e2014-12-14 15:20:10 -0800625 virtual SkLight* transform(const SkMatrix& matrix) const SK_OVERRIDE {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000626 return new SkDistantLight(direction(), color());
627 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000628 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000629 writePoint3(fDirection, buffer);
630 }
631
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000632private:
djsollen@google.com08337772012-06-26 14:33:13 +0000633 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000634 SkPoint3 fDirection;
635};
636
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000637///////////////////////////////////////////////////////////////////////////////
638
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000639class SkPointLight : public SkLight {
640public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000641 SkPointLight(const SkPoint3& location, SkColor color)
642 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000643
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000644 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
645 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
646 fLocation.fY - SkIntToScalar(y),
647 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
648 direction.normalize();
649 return direction;
650 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000651 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
tfarina912ed6e2014-12-14 15:20:10 -0800652 virtual LightType type() const SK_OVERRIDE { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000653 const SkPoint3& location() const { return fLocation; }
654 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000655#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000656 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000657#else
658 SkDEBUGFAIL("Should not call in GPU-less build");
659 return NULL;
660#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000661 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000662 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000663 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000664 if (other.type() != kPoint_LightType) {
665 return false;
666 }
667 const SkPointLight& o = static_cast<const SkPointLight&>(other);
668 return INHERITED::isEqual(other) &&
669 fLocation == o.fLocation;
670 }
tfarina912ed6e2014-12-14 15:20:10 -0800671 virtual SkLight* transform(const SkMatrix& matrix) const SK_OVERRIDE {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000672 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
673 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000674 // Use X scale and Y scale on Z and average the result
675 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
676 matrix.mapVectors(&locationZ, 1);
677 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000678 return new SkPointLight(location, color());
679 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000680
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000681 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000682 fLocation = readPoint3(buffer);
683 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000684
685protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000686 SkPointLight(const SkPoint3& location, const SkPoint3& color)
687 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000688 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000689 writePoint3(fLocation, buffer);
690 }
691
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000692private:
djsollen@google.com08337772012-06-26 14:33:13 +0000693 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000694 SkPoint3 fLocation;
695};
696
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000697///////////////////////////////////////////////////////////////////////////////
698
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000699class SkSpotLight : public SkLight {
700public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000701 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
702 : INHERITED(color),
703 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000705 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000706 {
707 fS = target - location;
708 fS.normalize();
709 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000710 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
712 fConeScale = SkScalarInvert(antiAliasThreshold);
713 }
djsollen@google.com08337772012-06-26 14:33:13 +0000714
tfarina912ed6e2014-12-14 15:20:10 -0800715 virtual SkLight* transform(const SkMatrix& matrix) const SK_OVERRIDE {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000716 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
717 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000718 // Use X scale and Y scale on Z and average the result
719 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
720 matrix.mapVectors(&locationZ, 1);
721 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000722 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
723 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000724 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
725 matrix.mapVectors(&targetZ, 1);
726 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
727 SkPoint3 s = target - location;
728 s.normalize();
729 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000730 }
731
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000732 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
733 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
734 fLocation.fY - SkIntToScalar(y),
735 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
736 direction.normalize();
737 return direction;
738 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000739 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000740 SkScalar cosAngle = -surfaceToLight.dot(fS);
741 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000742 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743 }
744 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
745 if (cosAngle < fCosInnerConeAngle) {
746 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000747 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000748 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000749 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000750 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000751 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000752#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000753 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000754#else
755 SkDEBUGFAIL("Should not call in GPU-less build");
756 return NULL;
757#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000758 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000759 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
tfarina912ed6e2014-12-14 15:20:10 -0800760 virtual LightType type() const SK_OVERRIDE { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000761 const SkPoint3& location() const { return fLocation; }
762 const SkPoint3& target() const { return fTarget; }
763 SkScalar specularExponent() const { return fSpecularExponent; }
764 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
765 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
766 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000767 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000768
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000769 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000770 fLocation = readPoint3(buffer);
771 fTarget = readPoint3(buffer);
772 fSpecularExponent = buffer.readScalar();
773 fCosOuterConeAngle = buffer.readScalar();
774 fCosInnerConeAngle = buffer.readScalar();
775 fConeScale = buffer.readScalar();
776 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000777 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
778 SkScalarIsFinite(fCosOuterConeAngle) &&
779 SkScalarIsFinite(fCosInnerConeAngle) &&
780 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000781 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000782protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000783 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
784 : INHERITED(color),
785 fLocation(location),
786 fTarget(target),
787 fSpecularExponent(specularExponent),
788 fCosOuterConeAngle(cosOuterConeAngle),
789 fCosInnerConeAngle(cosInnerConeAngle),
790 fConeScale(coneScale),
791 fS(s)
792 {
793 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000794 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000795 writePoint3(fLocation, buffer);
796 writePoint3(fTarget, buffer);
797 buffer.writeScalar(fSpecularExponent);
798 buffer.writeScalar(fCosOuterConeAngle);
799 buffer.writeScalar(fCosInnerConeAngle);
800 buffer.writeScalar(fConeScale);
801 writePoint3(fS, buffer);
802 }
803
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000804 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000805 if (other.type() != kSpot_LightType) {
806 return false;
807 }
808
809 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
810 return INHERITED::isEqual(other) &&
811 fLocation == o.fLocation &&
812 fTarget == o.fTarget &&
813 fSpecularExponent == o.fSpecularExponent &&
814 fCosOuterConeAngle == o.fCosOuterConeAngle;
815 }
816
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000817private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000818 static const SkScalar kSpecularExponentMin;
819 static const SkScalar kSpecularExponentMax;
820
djsollen@google.com08337772012-06-26 14:33:13 +0000821 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000822 SkPoint3 fLocation;
823 SkPoint3 fTarget;
824 SkScalar fSpecularExponent;
825 SkScalar fCosOuterConeAngle;
826 SkScalar fCosInnerConeAngle;
827 SkScalar fConeScale;
828 SkPoint3 fS;
829};
830
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000831// According to the spec, the specular term should be in the range [1, 128] :
832// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000833const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
834const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000835
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000836///////////////////////////////////////////////////////////////////////////////
837
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000838void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000839 // Write type first, then baseclass, then subclass.
840 buffer.writeInt(this->type());
841 writePoint3(fColor, buffer);
842 this->onFlattenLight(buffer);
843}
844
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000845/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000846 // Read type first.
847 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
848 switch (type) {
849 // Each of these constructors must first call SkLight's, so we'll read the baseclass
850 // then subclass, same order as flattenLight.
851 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
852 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
853 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
854 default:
855 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000856 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000857 return NULL;
858 }
859}
860///////////////////////////////////////////////////////////////////////////////
861
senorblanco9ea3d572014-07-08 09:16:22 -0700862SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700863 SkImageFilter* input, const CropRect* cropRect,
864 uint32_t uniqueID)
865 : INHERITED(1, &input, cropRect, uniqueID)
reed9fa60da2014-08-21 07:59:51 -0700866 , fLight(SkRef(light))
867 , fSurfaceScale(surfaceScale / 255)
868{}
869
870SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
871 SkColor lightColor,
872 SkScalar surfaceScale,
873 SkScalar kd,
874 SkImageFilter* input,
875 const CropRect* cropRect) {
876 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
877 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000878}
879
reed9fa60da2014-08-21 07:59:51 -0700880SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
881 SkColor lightColor,
882 SkScalar surfaceScale,
883 SkScalar kd,
884 SkImageFilter* input,
885 const CropRect* cropRect) {
886 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
887 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000888}
889
reed9fa60da2014-08-21 07:59:51 -0700890SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
891 const SkPoint3& target,
892 SkScalar specularExponent,
893 SkScalar cutoffAngle,
894 SkColor lightColor,
895 SkScalar surfaceScale,
896 SkScalar kd,
897 SkImageFilter* input,
898 const CropRect* cropRect) {
899 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
900 cutoffAngle, lightColor)));
901 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902}
903
reed9fa60da2014-08-21 07:59:51 -0700904SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
905 SkColor lightColor,
906 SkScalar surfaceScale,
907 SkScalar ks,
908 SkScalar shine,
909 SkImageFilter* input,
910 const CropRect* cropRect) {
911 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
912 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000913}
914
reed9fa60da2014-08-21 07:59:51 -0700915SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
916 SkColor lightColor,
917 SkScalar surfaceScale,
918 SkScalar ks,
919 SkScalar shine,
920 SkImageFilter* input,
921 const CropRect* cropRect) {
922 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
923 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000924}
925
reed9fa60da2014-08-21 07:59:51 -0700926SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
927 const SkPoint3& target,
928 SkScalar specularExponent,
929 SkScalar cutoffAngle,
930 SkColor lightColor,
931 SkScalar surfaceScale,
932 SkScalar ks,
933 SkScalar shine,
934 SkImageFilter* input,
935 const CropRect* cropRect) {
936 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
937 cutoffAngle, lightColor)));
938 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000939}
940
reed9fa60da2014-08-21 07:59:51 -0700941SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000942
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000943void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000944 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000945 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700946 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000947}
948
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000949///////////////////////////////////////////////////////////////////////////////
950
reed9fa60da2014-08-21 07:59:51 -0700951SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700952 SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -0700953 if (NULL == light) {
954 return NULL;
955 }
956 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
957 return NULL;
958 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000959 // According to the spec, kd can be any non-negative number :
960 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700961 if (kd < 0) {
962 return NULL;
963 }
senorblanco5e5f9482014-08-26 12:27:12 -0700964 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -0700965}
966
senorblanco5e5f9482014-08-26 12:27:12 -0700967SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
968 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -0700969 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000970{
971}
972
reed9fa60da2014-08-21 07:59:51 -0700973SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
974 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
975 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
976 SkScalar surfaceScale = buffer.readScalar();
977 SkScalar kd = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -0700978 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -0700979}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000981void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000982 this->INHERITED::flatten(buffer);
983 buffer.writeScalar(fKD);
984}
985
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000986bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
987 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000988 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000989 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000990 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000991 SkImageFilter* input = getInput(0);
992 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000993 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000994 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000995 return false;
996 }
997
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000998 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000999 return false;
1000 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001001 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001002 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001003 return false;
1004 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001005
1006 if (bounds.width() < 2 || bounds.height() < 2) {
1007 return false;
1008 }
1009
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001010 SkAutoLockPixels alp(src);
1011 if (!src.getPixels()) {
1012 return false;
1013 }
1014
reed84825042014-09-02 12:50:45 -07001015 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001016 return false;
1017 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001018
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001019 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001020
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001021 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001022 offset->fX = bounds.left();
1023 offset->fY = bounds.top();
1024 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001025 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001026 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001027 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001028 break;
1029 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001030 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001031 break;
1032 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001033 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001034 break;
1035 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001036
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001037 return true;
1038}
1039
robertphillipsf3f5bad2014-12-19 13:49:15 -08001040#ifndef SK_IGNORE_TO_STRING
1041void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1042 str->appendf("SkDiffuseLightingImageFilter: (");
1043 str->appendf("kD: %f\n", fKD);
1044 str->append(")");
1045}
1046#endif
1047
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001048#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001049bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1050 GrTexture* texture,
1051 const SkMatrix& matrix,
1052 const SkIRect&) const {
1053 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001054 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001055 *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001056 }
1057 return true;
1058}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001059#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001060
1061///////////////////////////////////////////////////////////////////////////////
1062
reed9fa60da2014-08-21 07:59:51 -07001063SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -07001064 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -07001065 if (NULL == light) {
1066 return NULL;
1067 }
1068 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1069 return NULL;
1070 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001071 // According to the spec, ks can be any non-negative number :
1072 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001073 if (ks < 0) {
1074 return NULL;
1075 }
1076 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco5e5f9482014-08-26 12:27:12 -07001077 (light, surfaceScale, ks, shininess, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -07001078}
1079
senorblanco5e5f9482014-08-26 12:27:12 -07001080SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
1081 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -07001082 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001083 fShininess(shininess)
1084{
1085}
1086
reed9fa60da2014-08-21 07:59:51 -07001087SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1088 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1089 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1090 SkScalar surfaceScale = buffer.readScalar();
1091 SkScalar ks = buffer.readScalar();
1092 SkScalar shine = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -07001093 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -07001094}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001095
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001096void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001097 this->INHERITED::flatten(buffer);
1098 buffer.writeScalar(fKS);
1099 buffer.writeScalar(fShininess);
1100}
1101
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001102bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1103 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001104 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001105 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001106 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001107 SkImageFilter* input = getInput(0);
1108 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001109 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001110 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001111 return false;
1112 }
1113
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001114 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001115 return false;
1116 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001117
1118 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001119 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001120 return false;
1121 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001122
1123 if (bounds.width() < 2 || bounds.height() < 2) {
1124 return false;
1125 }
1126
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001127 SkAutoLockPixels alp(src);
1128 if (!src.getPixels()) {
1129 return false;
1130 }
1131
reed84825042014-09-02 12:50:45 -07001132 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001133 return false;
1134 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001135
1136 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001137 offset->fX = bounds.left();
1138 offset->fY = bounds.top();
1139 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001140 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001141 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001142 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001143 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001144 break;
1145 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001146 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001147 break;
1148 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001149 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001150 break;
1151 }
1152 return true;
1153}
1154
robertphillipsf3f5bad2014-12-19 13:49:15 -08001155#ifndef SK_IGNORE_TO_STRING
1156void SkSpecularLightingImageFilter::toString(SkString* str) const {
1157 str->appendf("SkSpecularLightingImageFilter: (");
1158 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1159 str->append(")");
1160}
1161#endif
1162
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001163#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001164bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1165 GrTexture* texture,
1166 const SkMatrix& matrix,
1167 const SkIRect&) const {
1168 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001169 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001170 *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001171 }
1172 return true;
1173}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001174#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001175
1176///////////////////////////////////////////////////////////////////////////////
1177
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001178#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001179
1180namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001181SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001182 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1183 SkScalarToFloat(random->nextSScalar1()),
1184 SkScalarToFloat(random->nextSScalar1()));
1185}
1186
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001187SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001188 int type = random->nextULessThan(3);
1189 switch (type) {
1190 case 0: {
1191 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1192 }
1193 case 1: {
1194 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1195 }
1196 case 2: {
1197 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1198 random_point3(random),
1199 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001200 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001201 random->nextU()));
1202 }
1203 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001204 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001205 return NULL;
1206 }
1207}
1208
1209}
1210
joshualittb0a8a372014-09-23 09:50:21 -07001211class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001212public:
joshualitteb2a6762014-12-04 11:35:33 -08001213 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001214 virtual ~GrGLLightingEffect();
1215
joshualitt15988992014-10-09 15:04:05 -07001216 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -07001217 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001218 const char* outputColor,
1219 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001220 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001221 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001222
joshualittb0a8a372014-09-23 09:50:21 -07001223 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001224
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001225 /**
1226 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1227 */
joshualittb0a8a372014-09-23 09:50:21 -07001228 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001230protected:
joshualitt15988992014-10-09 15:04:05 -07001231 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001232
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001233private:
joshualittb0a8a372014-09-23 09:50:21 -07001234 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001235
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001236 UniformHandle fImageIncrementUni;
1237 UniformHandle fSurfaceScaleUni;
1238 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001239};
1240
1241///////////////////////////////////////////////////////////////////////////////
1242
1243class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1244public:
joshualitteb2a6762014-12-04 11:35:33 -08001245 GrGLDiffuseLightingEffect(const GrProcessor&);
joshualitt15988992014-10-09 15:04:05 -07001246 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001247 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248
1249private:
1250 typedef GrGLLightingEffect INHERITED;
1251
bsalomon@google.com032b2212012-07-16 13:36:18 +00001252 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001253};
1254
1255///////////////////////////////////////////////////////////////////////////////
1256
1257class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1258public:
joshualitteb2a6762014-12-04 11:35:33 -08001259 GrGLSpecularLightingEffect(const GrProcessor&);
joshualitt15988992014-10-09 15:04:05 -07001260 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001261 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001262
1263private:
1264 typedef GrGLLightingEffect INHERITED;
1265
bsalomon@google.com032b2212012-07-16 13:36:18 +00001266 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001267 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001268};
1269
1270///////////////////////////////////////////////////////////////////////////////
1271
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001272GrLightingEffect::GrLightingEffect(GrTexture* texture,
1273 const SkLight* light,
1274 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001275 const SkMatrix& matrix)
bsalomon6267f812014-08-29 15:05:53 -07001276 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001277 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001278 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001279 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001280 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001281 if (light->requiresFragmentPosition()) {
1282 this->setWillReadFragmentPosition();
1283 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001284}
1285
1286GrLightingEffect::~GrLightingEffect() {
1287 fLight->unref();
1288}
1289
bsalomon0e08fc12014-10-15 08:19:04 -07001290bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001291 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001292 return fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001293 fSurfaceScale == s.fSurfaceScale;
1294}
1295
1296///////////////////////////////////////////////////////////////////////////////
1297
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001298GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1299 const SkLight* light,
1300 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001301 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001302 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001303 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001304 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001305}
1306
bsalomon0e08fc12014-10-15 08:19:04 -07001307bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001308 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001309 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001310 this->kd() == s.kd();
1311}
1312
joshualitteb2a6762014-12-04 11:35:33 -08001313void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1314 GrProcessorKeyBuilder* b) const {
1315 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1316}
1317
1318GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1319 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1320}
1321
joshualittb0a8a372014-09-23 09:50:21 -07001322GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001323
joshualittb0a8a372014-09-23 09:50:21 -07001324GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001325 GrContext* context,
1326 const GrDrawTargetCaps&,
1327 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001328 SkScalar surfaceScale = random->nextSScalar1();
1329 SkScalar kd = random->nextUScalar1();
1330 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001331 SkMatrix matrix;
1332 for (int i = 0; i < 9; i++) {
1333 matrix[i] = random->nextUScalar1();
1334 }
joshualittb0a8a372014-09-23 09:50:21 -07001335 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001336 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001337}
1338
1339
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001340///////////////////////////////////////////////////////////////////////////////
1341
joshualitteb2a6762014-12-04 11:35:33 -08001342GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001343 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001344 fLight = m.light()->createGLLight();
1345}
1346
1347GrGLLightingEffect::~GrGLLightingEffect() {
1348 delete fLight;
1349}
1350
joshualitt15988992014-10-09 15:04:05 -07001351void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001352 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001353 const char* outputColor,
1354 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001355 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001356 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001357 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001358 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001359 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001360 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001361 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001362 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001363 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001364 SkString lightFunc;
1365 this->emitLightFunc(builder, &lightFunc);
1366 static const GrGLShaderVar gSobelArgs[] = {
1367 GrGLShaderVar("a", kFloat_GrSLType),
1368 GrGLShaderVar("b", kFloat_GrSLType),
1369 GrGLShaderVar("c", kFloat_GrSLType),
1370 GrGLShaderVar("d", kFloat_GrSLType),
1371 GrGLShaderVar("e", kFloat_GrSLType),
1372 GrGLShaderVar("f", kFloat_GrSLType),
1373 GrGLShaderVar("scale", kFloat_GrSLType),
1374 };
1375 SkString sobelFuncName;
joshualitt15988992014-10-09 15:04:05 -07001376 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001377 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1378
1379 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001380 "sobel",
1381 SK_ARRAY_COUNT(gSobelArgs),
1382 gSobelArgs,
1383 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1384 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001385 static const GrGLShaderVar gPointToNormalArgs[] = {
1386 GrGLShaderVar("x", kFloat_GrSLType),
1387 GrGLShaderVar("y", kFloat_GrSLType),
1388 GrGLShaderVar("scale", kFloat_GrSLType),
1389 };
1390 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001391 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001392 "pointToNormal",
1393 SK_ARRAY_COUNT(gPointToNormalArgs),
1394 gPointToNormalArgs,
1395 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1396 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001397
1398 static const GrGLShaderVar gInteriorNormalArgs[] = {
1399 GrGLShaderVar("m", kFloat_GrSLType, 9),
1400 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1401 };
1402 SkString interiorNormalBody;
1403 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1404 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1405 "\t surfaceScale);\n",
1406 pointToNormalName.c_str(),
1407 sobelFuncName.c_str(),
1408 sobelFuncName.c_str());
1409 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001410 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001411 "interiorNormal",
1412 SK_ARRAY_COUNT(gInteriorNormalArgs),
1413 gInteriorNormalArgs,
1414 interiorNormalBody.c_str(),
1415 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001416
joshualitt30ba4362014-08-21 20:18:45 -07001417 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1418 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001419
1420 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1421 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1422
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001423 int index = 0;
1424 for (int dy = -1; dy <= 1; dy++) {
1425 for (int dx = -1; dx <= 1; dx++) {
1426 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001427 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001428 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1429 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1430 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001431 }
1432 }
joshualitt30ba4362014-08-21 20:18:45 -07001433 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001434 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001435 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001436 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001437 fsBuilder->codeAppend(";\n");
1438 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001439 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001440 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001441 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001442 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001443 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001444 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001445}
1446
joshualittb0a8a372014-09-23 09:50:21 -07001447void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1448 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
1449 b->add32(proc.cast<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001450}
1451
kkinnunen7510b222014-07-30 00:04:16 -07001452void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001453 const GrProcessor& proc) {
1454 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001455 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001456 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001457 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1458 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001459 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001460 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001461}
1462
1463///////////////////////////////////////////////////////////////////////////////
1464
1465///////////////////////////////////////////////////////////////////////////////
1466
joshualitteb2a6762014-12-04 11:35:33 -08001467GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1468 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001469}
1470
joshualitt15988992014-10-09 15:04:05 -07001471void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001472 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001473 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001474 kFloat_GrSLType, kDefault_GrSLPrecision,
1475 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001476
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001477 static const GrGLShaderVar gLightArgs[] = {
1478 GrGLShaderVar("normal", kVec3f_GrSLType),
1479 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1480 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1481 };
1482 SkString lightBody;
1483 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1484 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001485 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1486 "light",
1487 SK_ARRAY_COUNT(gLightArgs),
1488 gLightArgs,
1489 lightBody.c_str(),
1490 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001491}
1492
kkinnunen7510b222014-07-30 00:04:16 -07001493void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001494 const GrProcessor& proc) {
1495 INHERITED::setData(pdman, proc);
1496 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001497 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001498}
1499
1500///////////////////////////////////////////////////////////////////////////////
1501
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001502GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1503 const SkLight* light,
1504 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001505 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001506 SkScalar ks,
1507 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001508 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001509 fKS(ks),
1510 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001511 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001512}
1513
bsalomon0e08fc12014-10-15 08:19:04 -07001514bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001515 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001516 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001517 this->ks() == s.ks() &&
1518 this->shininess() == s.shininess();
1519}
1520
joshualitteb2a6762014-12-04 11:35:33 -08001521void GrSpecularLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1522 GrProcessorKeyBuilder* b) const {
1523 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1524}
1525
1526GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1527 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1528}
1529
joshualittb0a8a372014-09-23 09:50:21 -07001530GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001531
joshualittb0a8a372014-09-23 09:50:21 -07001532GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1533 GrContext* context,
1534 const GrDrawTargetCaps&,
1535 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001536 SkScalar surfaceScale = random->nextSScalar1();
1537 SkScalar ks = random->nextUScalar1();
1538 SkScalar shininess = random->nextUScalar1();
1539 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001540 SkMatrix matrix;
1541 for (int i = 0; i < 9; i++) {
1542 matrix[i] = random->nextUScalar1();
1543 }
joshualittb0a8a372014-09-23 09:50:21 -07001544 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001545 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001546}
1547
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001548///////////////////////////////////////////////////////////////////////////////
1549
joshualitteb2a6762014-12-04 11:35:33 -08001550GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1551 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001552}
1553
joshualitt15988992014-10-09 15:04:05 -07001554void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001555 const char* ks;
1556 const char* shininess;
1557
joshualitt30ba4362014-08-21 20:18:45 -07001558 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001559 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001560 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001561 kFloat_GrSLType, kDefault_GrSLPrecision, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001562
1563 static const GrGLShaderVar gLightArgs[] = {
1564 GrGLShaderVar("normal", kVec3f_GrSLType),
1565 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1566 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1567 };
1568 SkString lightBody;
1569 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1570 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001571 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1572 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001573 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1574 "light",
1575 SK_ARRAY_COUNT(gLightArgs),
1576 gLightArgs,
1577 lightBody.c_str(),
1578 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001579}
1580
kkinnunen7510b222014-07-30 00:04:16 -07001581void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001582 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001583 INHERITED::setData(pdman, effect);
1584 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001585 pdman.set1f(fKSUni, spec.ks());
1586 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001587}
1588
1589///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001590void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001591 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001592 kVec3f_GrSLType, kDefault_GrSLPrecision,
1593 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001594}
1595
joshualitt15988992014-10-09 15:04:05 -07001596void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001597 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001598 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001599}
1600
kkinnunen7510b222014-07-30 00:04:16 -07001601void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001602 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001603 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001604}
1605
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001606///////////////////////////////////////////////////////////////////////////////
1607
kkinnunen7510b222014-07-30 00:04:16 -07001608void GrGLDistantLight::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::kDistant_LightType);
1612 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001613 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001614}
1615
joshualitt15988992014-10-09 15:04:05 -07001616void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001617 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001618 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1619 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001620 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001621 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001622}
1623
1624///////////////////////////////////////////////////////////////////////////////
1625
kkinnunen7510b222014-07-30 00:04:16 -07001626void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001627 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001628 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001629 SkASSERT(light->type() == SkLight::kPoint_LightType);
1630 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001631 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001632}
1633
joshualitt15988992014-10-09 15:04:05 -07001634void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001635 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001636 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1637 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001638 "LightLocation", &loc);
joshualitt15988992014-10-09 15:04:05 -07001639 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001640 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1641 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001642}
1643
1644///////////////////////////////////////////////////////////////////////////////
1645
kkinnunen7510b222014-07-30 00:04:16 -07001646void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001647 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001648 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001649 SkASSERT(light->type() == SkLight::kSpot_LightType);
1650 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001651 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1652 pdman.set1f(fExponentUni, spotLight->specularExponent());
1653 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1654 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1655 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1656 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001657}
1658
joshualitt15988992014-10-09 15:04:05 -07001659void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001660 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001661 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001662 kVec3f_GrSLType, kDefault_GrSLPrecision,
1663 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001664
joshualitt15988992014-10-09 15:04:05 -07001665 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001666 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1667 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001668}
1669
joshualitt15988992014-10-09 15:04:05 -07001670void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001671 const char *surfaceToLight) {
1672
1673 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1674
1675 const char* exponent;
1676 const char* cosInner;
1677 const char* cosOuter;
1678 const char* coneScale;
1679 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001680 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001681 kFloat_GrSLType, kDefault_GrSLPrecision,
1682 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001683 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001684 kFloat_GrSLType, kDefault_GrSLPrecision,
1685 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001686 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001687 kFloat_GrSLType, kDefault_GrSLPrecision,
1688 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001689 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001690 kFloat_GrSLType, kDefault_GrSLPrecision,
1691 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001692 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001693 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001694
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001695 static const GrGLShaderVar gLightColorArgs[] = {
1696 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1697 };
1698 SkString lightColorBody;
1699 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1700 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1701 lightColorBody.appendf("\t\treturn vec3(0);\n");
1702 lightColorBody.appendf("\t}\n");
1703 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1704 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1705 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1706 color, cosOuter, coneScale);
1707 lightColorBody.appendf("\t}\n");
1708 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt15988992014-10-09 15:04:05 -07001709 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001710 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001711 "lightColor",
1712 SK_ARRAY_COUNT(gLightColorArgs),
1713 gLightColorArgs,
1714 lightColorBody.c_str(),
1715 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001716
joshualitt30ba4362014-08-21 20:18:45 -07001717 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001718}
1719
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001720#endif
1721
djsollen@google.com08337772012-06-26 14:33:13 +00001722SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1723 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1724 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001725SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END