blob: a280d5f5762643c1f6273222f23554fb32bca8d6 [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
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000018#include "effects/GrSingleTextureEffect.h"
joshualittb0a8a372014-09-23 09:50:21 -070019#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070020#include "gl/builders/GrGLProgramBuilder.h"
joshualittb0a8a372014-09-23 09:50:21 -070021#include "GrProcessor.h"
22#include "GrTBackendProcessorFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000023
24class GrGLDiffuseLightingEffect;
25class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000026
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000027// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070028typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000029#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000030
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000031namespace {
32
33const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
34const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000035const SkScalar gOneHalf = 0.5f;
36const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000038#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070039void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
40 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000041 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070042 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000043}
44
joshualittb0a8a372014-09-23 09:50:21 -070045void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
46 const SkPoint3& point) {
kkinnunen7510b222014-07-30 00:04:16 -070047 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000048}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000049#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000050
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000051// Shift matrix components to the left, as we advance pixels to the right.
52inline void shiftMatrixLeft(int m[9]) {
53 m[0] = m[1];
54 m[3] = m[4];
55 m[6] = m[7];
56 m[1] = m[2];
57 m[4] = m[5];
58 m[7] = m[8];
59}
60
61class DiffuseLightingType {
62public:
63 DiffuseLightingType(SkScalar kd)
64 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070065 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
66 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000067 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
68 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
69 SkPoint3 color(lightColor * colorScale);
70 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000071 SkClampMax(SkScalarRoundToInt(color.fX), 255),
72 SkClampMax(SkScalarRoundToInt(color.fY), 255),
73 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000074 }
75private:
76 SkScalar fKD;
77};
78
79class SpecularLightingType {
80public:
81 SpecularLightingType(SkScalar ks, SkScalar shininess)
82 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070083 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
84 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 SkPoint3 halfDir(surfaceTolight);
86 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
87 halfDir.normalize();
88 SkScalar colorScale = SkScalarMul(fKS,
89 SkScalarPow(normal.dot(halfDir), fShininess));
90 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
91 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000092 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
93 SkClampMax(SkScalarRoundToInt(color.fX), 255),
94 SkClampMax(SkScalarRoundToInt(color.fY), 255),
95 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000096 }
97private:
98 SkScalar fKS;
99 SkScalar fShininess;
100};
101
102inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
103 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
104}
105
106inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
107 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
108 SkScalarMul(-y, surfaceScale),
109 SK_Scalar1);
110 vector.normalize();
111 return vector;
112}
113
114inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
116 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
117 surfaceScale);
118}
119
120inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
122 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
123 surfaceScale);
124}
125
126inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
128 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
129 surfaceScale);
130}
131
132inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
134 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
135 surfaceScale);
136}
137
138
139inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
141 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
142 surfaceScale);
143}
144
145inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
147 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
148 surfaceScale);
149}
150
151inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
153 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
159 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
160 surfaceScale);
161}
162
163inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
165 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
166 surfaceScale);
167}
168
joshualittb0a8a372014-09-23 09:50:21 -0700169template <class LightingType, class LightType> void lightBitmap(
170 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
171 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000172 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000173 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000174 int left = bounds.left(), right = bounds.right();
175 int bottom = bounds.bottom();
176 int y = bounds.top();
177 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000178 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000179 int x = left;
180 const SkPMColor* row1 = src.getAddr32(x, y);
181 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000182 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000183 m[4] = SkGetPackedA32(*row1++);
184 m[5] = SkGetPackedA32(*row1++);
185 m[7] = SkGetPackedA32(*row2++);
186 m[8] = SkGetPackedA32(*row2++);
187 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700188 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
189 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000190 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 {
192 shiftMatrixLeft(m);
193 m[5] = SkGetPackedA32(*row1++);
194 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000195 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700196 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
197 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000198 }
199 shiftMatrixLeft(m);
200 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700201 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
202 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000203 }
204
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000205 for (++y; y < bottom - 1; ++y) {
206 int x = left;
207 const SkPMColor* row0 = src.getAddr32(x, y - 1);
208 const SkPMColor* row1 = src.getAddr32(x, y);
209 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000211 m[1] = SkGetPackedA32(*row0++);
212 m[2] = SkGetPackedA32(*row0++);
213 m[4] = SkGetPackedA32(*row1++);
214 m[5] = SkGetPackedA32(*row1++);
215 m[7] = SkGetPackedA32(*row2++);
216 m[8] = SkGetPackedA32(*row2++);
217 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700218 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
219 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000220 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 shiftMatrixLeft(m);
222 m[2] = SkGetPackedA32(*row0++);
223 m[5] = SkGetPackedA32(*row1++);
224 m[8] = SkGetPackedA32(*row2++);
225 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700226 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
227 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000228 }
229 shiftMatrixLeft(m);
230 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700231 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
232 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 }
234
235 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000236 int x = left;
237 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
238 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 int m[9];
240 m[1] = SkGetPackedA32(*row0++);
241 m[2] = SkGetPackedA32(*row0++);
242 m[4] = SkGetPackedA32(*row1++);
243 m[5] = SkGetPackedA32(*row1++);
244 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700245 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
246 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000247 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 {
249 shiftMatrixLeft(m);
250 m[2] = SkGetPackedA32(*row0++);
251 m[5] = SkGetPackedA32(*row1++);
252 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700253 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
254 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000255 }
256 shiftMatrixLeft(m);
257 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700258 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
259 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000260 }
261}
262
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000263SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SkPoint3 point;
265 point.fX = buffer.readScalar();
266 point.fY = buffer.readScalar();
267 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000268 buffer.validate(SkScalarIsFinite(point.fX) &&
269 SkScalarIsFinite(point.fY) &&
270 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271 return point;
272};
273
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000274void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000275 buffer.writeScalar(point.fX);
276 buffer.writeScalar(point.fY);
277 buffer.writeScalar(point.fZ);
278};
279
280class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
281public:
reed9fa60da2014-08-21 07:59:51 -0700282 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco5e5f9482014-08-26 12:27:12 -0700283 const CropRect*, uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700284
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000285 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000286 SkScalar kd() const { return fKD; }
287
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000288protected:
reed9fa60da2014-08-21 07:59:51 -0700289 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700290 SkScalar kd, SkImageFilter* input, const CropRect* cropRect,
291 uint32_t uniqueID);
reed9fa60da2014-08-21 07:59:51 -0700292#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000293 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -0700294#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000295 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000296 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000297 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000298#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700299 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
300 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000301#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000302
303private:
reed9fa60da2014-08-21 07:59:51 -0700304 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000305 typedef SkLightingImageFilter INHERITED;
306 SkScalar fKD;
307};
308
309class SkSpecularLightingImageFilter : public SkLightingImageFilter {
310public:
reed9fa60da2014-08-21 07:59:51 -0700311 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
joshualittb0a8a372014-09-23 09:50:21 -0700312 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*,
313 uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700314
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000315 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
316
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000317 SkScalar ks() const { return fKS; }
318 SkScalar shininess() const { return fShininess; }
319
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000320protected:
reed9fa60da2014-08-21 07:59:51 -0700321 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco5e5f9482014-08-26 12:27:12 -0700322 SkScalar shininess, SkImageFilter* input, const CropRect*,
323 uint32_t uniqueID);
reed9fa60da2014-08-21 07:59:51 -0700324#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000325 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -0700326#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000327 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000328 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000329 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000330#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700331 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
332 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000333#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000334
335private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000336 SkScalar fKS;
337 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700338 friend class SkLightingImageFilter;
339 typedef SkLightingImageFilter INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000340};
341
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000342#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000343
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000344class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000345public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000346 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000347 virtual ~GrLightingEffect();
348
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000349 const SkLight* light() const { return fLight; }
350 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000351 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000352
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000353protected:
bsalomon0e08fc12014-10-15 08:19:04 -0700354 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000355
egdaniel1a8ecdf2014-10-03 06:24:12 -0700356 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
357 // lighting shaders are complicated. We just throw up our hands.
egdanielccb2e382014-10-13 12:53:46 -0700358 inout->mulByUnknownColor();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700359 }
360
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000361private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000362 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000363 const SkLight* fLight;
364 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000365 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000366};
367
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000368class GrDiffuseLightingEffect : public GrLightingEffect {
369public:
joshualittb0a8a372014-09-23 09:50:21 -0700370 static GrFragmentProcessor* Create(GrTexture* texture,
371 const SkLight* light,
372 SkScalar surfaceScale,
373 const SkMatrix& matrix,
374 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700375 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
376 light,
377 surfaceScale,
378 matrix,
379 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000380 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000381
382 static const char* Name() { return "DiffuseLighting"; }
383
joshualittb0a8a372014-09-23 09:50:21 -0700384 typedef GrGLDiffuseLightingEffect GLProcessor;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000385
joshualittb0a8a372014-09-23 09:50:21 -0700386 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000387 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000388
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000389private:
bsalomon0e08fc12014-10-15 08:19:04 -0700390 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000391
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000392 GrDiffuseLightingEffect(GrTexture* texture,
393 const SkLight* light,
394 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000395 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000396 SkScalar kd);
397
joshualittb0a8a372014-09-23 09:50:21 -0700398 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000399 typedef GrLightingEffect INHERITED;
400 SkScalar fKD;
401};
402
403class GrSpecularLightingEffect : public GrLightingEffect {
404public:
joshualittb0a8a372014-09-23 09:50:21 -0700405 static GrFragmentProcessor* Create(GrTexture* texture,
406 const SkLight* light,
407 SkScalar surfaceScale,
408 const SkMatrix& matrix,
409 SkScalar ks,
410 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700411 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
412 light,
413 surfaceScale,
414 matrix,
415 ks,
416 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000417 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000418 static const char* Name() { return "SpecularLighting"; }
419
joshualittb0a8a372014-09-23 09:50:21 -0700420 typedef GrGLSpecularLightingEffect GLProcessor;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000421
joshualittb0a8a372014-09-23 09:50:21 -0700422 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000423 SkScalar ks() const { return fKS; }
424 SkScalar shininess() const { return fShininess; }
425
426private:
bsalomon0e08fc12014-10-15 08:19:04 -0700427 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000428
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000429 GrSpecularLightingEffect(GrTexture* texture,
430 const SkLight* light,
431 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000432 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000433 SkScalar ks,
434 SkScalar shininess);
435
joshualittb0a8a372014-09-23 09:50:21 -0700436 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000437 typedef GrLightingEffect INHERITED;
438 SkScalar fKS;
439 SkScalar fShininess;
440};
441
442///////////////////////////////////////////////////////////////////////////////
443
444class GrGLLight {
445public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000446 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000447
448 /**
449 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
450 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
451 */
joshualitt15988992014-10-09 15:04:05 -0700452 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000453
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000454 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000455 * These two functions are called from GrGLLightingEffect's emitCode() function.
456 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
457 * the light. The expression will be used in the FS. emitLightColor writes an expression into
458 * the FS that is the color of the light. Either function may add functions and/or uniforms to
459 * the FS. The default of emitLightColor appends the name of the constant light color uniform
460 * and so this function only needs to be overridden if the light color varies spatially.
461 */
joshualitt15988992014-10-09 15:04:05 -0700462 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
463 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000464
465 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
466 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700467 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000468 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000469
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000470protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000471 /**
472 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
473 * function.
474 */
475 UniformHandle lightColorUni() const { return fColorUni; }
476
477private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000478 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000479
480 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000481};
482
483///////////////////////////////////////////////////////////////////////////////
484
485class GrGLDistantLight : public GrGLLight {
486public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000487 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700488 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000489 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700490 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000491
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492private:
493 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000494 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000495};
496
497///////////////////////////////////////////////////////////////////////////////
498
499class GrGLPointLight : public GrGLLight {
500public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000501 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700502 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000503 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700504 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000505
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506private:
507 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000508 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000509};
510
511///////////////////////////////////////////////////////////////////////////////
512
513class GrGLSpotLight : public GrGLLight {
514public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000515 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700516 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000517 const SkLight* light) const SK_OVERRIDE;
joshualitt15988992014-10-09 15:04:05 -0700518 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
519 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000520
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000521private:
522 typedef GrGLLight INHERITED;
523
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000524 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000525 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000526 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000527 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000528 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000529 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000530 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000531};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000532#else
533
534class GrGLLight;
535
536#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000537
538};
539
540///////////////////////////////////////////////////////////////////////////////
541
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000542class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000543public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000544 SK_DECLARE_INST_COUNT(SkLight)
545
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000546 enum LightType {
547 kDistant_LightType,
548 kPoint_LightType,
549 kSpot_LightType,
550 };
551 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000552 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000553 virtual GrGLLight* createGLLight() const = 0;
554 virtual bool isEqual(const SkLight& other) const {
555 return fColor == other.fColor;
556 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000557 // Called to know whether the generated GrGLLight will require access to the fragment position.
558 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000559 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000561 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000562 void flattenLight(SkWriteBuffer& buffer) const;
563 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000564
djsollen@google.com08337772012-06-26 14:33:13 +0000565protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000566 SkLight(SkColor color)
567 : fColor(SkIntToScalar(SkColorGetR(color)),
568 SkIntToScalar(SkColorGetG(color)),
569 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000570 SkLight(const SkPoint3& color)
571 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000572 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000573 fColor = readPoint3(buffer);
574 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000575
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000576 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000577
djsollen@google.com08337772012-06-26 14:33:13 +0000578
579private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000580 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000581 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000582};
583
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000584///////////////////////////////////////////////////////////////////////////////
585
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586class SkDistantLight : public SkLight {
587public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000588 SkDistantLight(const SkPoint3& direction, SkColor color)
589 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000590 }
djsollen@google.com08337772012-06-26 14:33:13 +0000591
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000592 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
593 return fDirection;
594 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000595 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000596 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000597 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000598 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
599#if SK_SUPPORT_GPU
600 return SkNEW(GrGLDistantLight);
601#else
602 SkDEBUGFAIL("Should not call in GPU-less build");
603 return NULL;
604#endif
605 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000606 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
607
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000608 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
609 if (other.type() != kDistant_LightType) {
610 return false;
611 }
612
613 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
614 return INHERITED::isEqual(other) &&
615 fDirection == o.fDirection;
616 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000617
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000618 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000619 fDirection = readPoint3(buffer);
620 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000621
djsollen@google.com08337772012-06-26 14:33:13 +0000622protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000623 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
624 : INHERITED(color), fDirection(direction) {
625 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000626 virtual SkLight* transform(const SkMatrix& matrix) const {
627 return new SkDistantLight(direction(), color());
628 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000629 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000630 writePoint3(fDirection, buffer);
631 }
632
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000633private:
djsollen@google.com08337772012-06-26 14:33:13 +0000634 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000635 SkPoint3 fDirection;
636};
637
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638///////////////////////////////////////////////////////////////////////////////
639
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000640class SkPointLight : public SkLight {
641public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000642 SkPointLight(const SkPoint3& location, SkColor color)
643 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000644
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000645 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
646 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
647 fLocation.fY - SkIntToScalar(y),
648 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
649 direction.normalize();
650 return direction;
651 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000652 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000653 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000654 const SkPoint3& location() const { return fLocation; }
655 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000656#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000657 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000658#else
659 SkDEBUGFAIL("Should not call in GPU-less build");
660 return NULL;
661#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000663 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000664 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000665 if (other.type() != kPoint_LightType) {
666 return false;
667 }
668 const SkPointLight& o = static_cast<const SkPointLight&>(other);
669 return INHERITED::isEqual(other) &&
670 fLocation == o.fLocation;
671 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000672 virtual SkLight* transform(const SkMatrix& matrix) const {
673 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
674 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000675 // Use X scale and Y scale on Z and average the result
676 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
677 matrix.mapVectors(&locationZ, 1);
678 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000679 return new SkPointLight(location, color());
680 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000681
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000682 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000683 fLocation = readPoint3(buffer);
684 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000685
686protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000687 SkPointLight(const SkPoint3& location, const SkPoint3& color)
688 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000689 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000690 writePoint3(fLocation, buffer);
691 }
692
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000693private:
djsollen@google.com08337772012-06-26 14:33:13 +0000694 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 SkPoint3 fLocation;
696};
697
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000698///////////////////////////////////////////////////////////////////////////////
699
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000700class SkSpotLight : public SkLight {
701public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000702 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
703 : INHERITED(color),
704 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000705 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000706 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000707 {
708 fS = target - location;
709 fS.normalize();
710 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000711 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
713 fConeScale = SkScalarInvert(antiAliasThreshold);
714 }
djsollen@google.com08337772012-06-26 14:33:13 +0000715
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000716 virtual SkLight* transform(const SkMatrix& matrix) const {
717 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
718 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000719 // Use X scale and Y scale on Z and average the result
720 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
721 matrix.mapVectors(&locationZ, 1);
722 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000723 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
724 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000725 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
726 matrix.mapVectors(&targetZ, 1);
727 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
728 SkPoint3 s = target - location;
729 s.normalize();
730 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000731 }
732
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
734 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
735 fLocation.fY - SkIntToScalar(y),
736 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
737 direction.normalize();
738 return direction;
739 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000740 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000741 SkScalar cosAngle = -surfaceToLight.dot(fS);
742 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000743 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000744 }
745 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
746 if (cosAngle < fCosInnerConeAngle) {
747 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000748 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000749 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000750 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000751 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000752 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000753#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000754 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000755#else
756 SkDEBUGFAIL("Should not call in GPU-less build");
757 return NULL;
758#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000759 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000760 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000761 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000762 const SkPoint3& location() const { return fLocation; }
763 const SkPoint3& target() const { return fTarget; }
764 SkScalar specularExponent() const { return fSpecularExponent; }
765 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
766 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
767 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000768 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000769
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000770 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000771 fLocation = readPoint3(buffer);
772 fTarget = readPoint3(buffer);
773 fSpecularExponent = buffer.readScalar();
774 fCosOuterConeAngle = buffer.readScalar();
775 fCosInnerConeAngle = buffer.readScalar();
776 fConeScale = buffer.readScalar();
777 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000778 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
779 SkScalarIsFinite(fCosOuterConeAngle) &&
780 SkScalarIsFinite(fCosInnerConeAngle) &&
781 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000782 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000783protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000784 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
785 : INHERITED(color),
786 fLocation(location),
787 fTarget(target),
788 fSpecularExponent(specularExponent),
789 fCosOuterConeAngle(cosOuterConeAngle),
790 fCosInnerConeAngle(cosInnerConeAngle),
791 fConeScale(coneScale),
792 fS(s)
793 {
794 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000795 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000796 writePoint3(fLocation, buffer);
797 writePoint3(fTarget, buffer);
798 buffer.writeScalar(fSpecularExponent);
799 buffer.writeScalar(fCosOuterConeAngle);
800 buffer.writeScalar(fCosInnerConeAngle);
801 buffer.writeScalar(fConeScale);
802 writePoint3(fS, buffer);
803 }
804
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000805 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000806 if (other.type() != kSpot_LightType) {
807 return false;
808 }
809
810 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
811 return INHERITED::isEqual(other) &&
812 fLocation == o.fLocation &&
813 fTarget == o.fTarget &&
814 fSpecularExponent == o.fSpecularExponent &&
815 fCosOuterConeAngle == o.fCosOuterConeAngle;
816 }
817
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000818private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000819 static const SkScalar kSpecularExponentMin;
820 static const SkScalar kSpecularExponentMax;
821
djsollen@google.com08337772012-06-26 14:33:13 +0000822 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000823 SkPoint3 fLocation;
824 SkPoint3 fTarget;
825 SkScalar fSpecularExponent;
826 SkScalar fCosOuterConeAngle;
827 SkScalar fCosInnerConeAngle;
828 SkScalar fConeScale;
829 SkPoint3 fS;
830};
831
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000832// According to the spec, the specular term should be in the range [1, 128] :
833// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000834const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
835const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000836
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000837///////////////////////////////////////////////////////////////////////////////
838
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000839void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000840 // Write type first, then baseclass, then subclass.
841 buffer.writeInt(this->type());
842 writePoint3(fColor, buffer);
843 this->onFlattenLight(buffer);
844}
845
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000846/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000847 // Read type first.
848 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
849 switch (type) {
850 // Each of these constructors must first call SkLight's, so we'll read the baseclass
851 // then subclass, same order as flattenLight.
852 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
853 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
854 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
855 default:
856 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000857 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000858 return NULL;
859 }
860}
861///////////////////////////////////////////////////////////////////////////////
862
senorblanco9ea3d572014-07-08 09:16:22 -0700863SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700864 SkImageFilter* input, const CropRect* cropRect,
865 uint32_t uniqueID)
866 : INHERITED(1, &input, cropRect, uniqueID)
reed9fa60da2014-08-21 07:59:51 -0700867 , fLight(SkRef(light))
868 , fSurfaceScale(surfaceScale / 255)
869{}
870
871SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
872 SkColor lightColor,
873 SkScalar surfaceScale,
874 SkScalar kd,
875 SkImageFilter* input,
876 const CropRect* cropRect) {
877 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
878 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000879}
880
reed9fa60da2014-08-21 07:59:51 -0700881SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
882 SkColor lightColor,
883 SkScalar surfaceScale,
884 SkScalar kd,
885 SkImageFilter* input,
886 const CropRect* cropRect) {
887 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
888 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000889}
890
reed9fa60da2014-08-21 07:59:51 -0700891SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
892 const SkPoint3& target,
893 SkScalar specularExponent,
894 SkScalar cutoffAngle,
895 SkColor lightColor,
896 SkScalar surfaceScale,
897 SkScalar kd,
898 SkImageFilter* input,
899 const CropRect* cropRect) {
900 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
901 cutoffAngle, lightColor)));
902 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000903}
904
reed9fa60da2014-08-21 07:59:51 -0700905SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
906 SkColor lightColor,
907 SkScalar surfaceScale,
908 SkScalar ks,
909 SkScalar shine,
910 SkImageFilter* input,
911 const CropRect* cropRect) {
912 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
913 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000914}
915
reed9fa60da2014-08-21 07:59:51 -0700916SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
917 SkColor lightColor,
918 SkScalar surfaceScale,
919 SkScalar ks,
920 SkScalar shine,
921 SkImageFilter* input,
922 const CropRect* cropRect) {
923 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
924 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000925}
926
reed9fa60da2014-08-21 07:59:51 -0700927SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
928 const SkPoint3& target,
929 SkScalar specularExponent,
930 SkScalar cutoffAngle,
931 SkColor lightColor,
932 SkScalar surfaceScale,
933 SkScalar ks,
934 SkScalar shine,
935 SkImageFilter* input,
936 const CropRect* cropRect) {
937 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
938 cutoffAngle, lightColor)));
939 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000940}
941
reed9fa60da2014-08-21 07:59:51 -0700942SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000943
reed9fa60da2014-08-21 07:59:51 -0700944#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000945SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000946 : INHERITED(1, buffer) {
reed9fa60da2014-08-21 07:59:51 -0700947 fLight.reset(SkLight::UnflattenLight(buffer));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000948 fSurfaceScale = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000949 buffer.validate(SkScalarIsFinite(fSurfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000950}
reed9fa60da2014-08-21 07:59:51 -0700951#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000952
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000953void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000954 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000955 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700956 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000957}
958
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000959///////////////////////////////////////////////////////////////////////////////
960
reed9fa60da2014-08-21 07:59:51 -0700961SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700962 SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -0700963 if (NULL == light) {
964 return NULL;
965 }
966 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
967 return NULL;
968 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000969 // According to the spec, kd can be any non-negative number :
970 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700971 if (kd < 0) {
972 return NULL;
973 }
senorblanco5e5f9482014-08-26 12:27:12 -0700974 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -0700975}
976
senorblanco5e5f9482014-08-26 12:27:12 -0700977SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
978 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -0700979 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980{
981}
982
reed9fa60da2014-08-21 07:59:51 -0700983#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000984SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000985 : INHERITED(buffer)
986{
987 fKD = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000988 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000989}
reed9fa60da2014-08-21 07:59:51 -0700990#endif
991
992SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
993 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
994 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
995 SkScalar surfaceScale = buffer.readScalar();
996 SkScalar kd = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -0700997 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -0700998}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000999
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001000void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001001 this->INHERITED::flatten(buffer);
1002 buffer.writeScalar(fKD);
1003}
1004
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001005bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1006 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001007 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001008 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001009 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001010 SkImageFilter* input = getInput(0);
1011 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001012 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001013 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001014 return false;
1015 }
1016
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001017 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001018 return false;
1019 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001020 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001021 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001022 return false;
1023 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001024
1025 if (bounds.width() < 2 || bounds.height() < 2) {
1026 return false;
1027 }
1028
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001029 SkAutoLockPixels alp(src);
1030 if (!src.getPixels()) {
1031 return false;
1032 }
1033
reed84825042014-09-02 12:50:45 -07001034 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001035 return false;
1036 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001037
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001038 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001039
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001040 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001041 offset->fX = bounds.left();
1042 offset->fY = bounds.top();
1043 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001044 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001045 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001046 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001047 break;
1048 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001049 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001050 break;
1051 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001052 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001053 break;
1054 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001055
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001056 return true;
1057}
1058
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001059#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001060bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1061 GrTexture* texture,
1062 const SkMatrix& matrix,
1063 const SkIRect&) const {
1064 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001065 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001066 *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001067 }
1068 return true;
1069}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001070#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001071
1072///////////////////////////////////////////////////////////////////////////////
1073
reed9fa60da2014-08-21 07:59:51 -07001074SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -07001075 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -07001076 if (NULL == light) {
1077 return NULL;
1078 }
1079 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1080 return NULL;
1081 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001082 // According to the spec, ks can be any non-negative number :
1083 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001084 if (ks < 0) {
1085 return NULL;
1086 }
1087 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco5e5f9482014-08-26 12:27:12 -07001088 (light, surfaceScale, ks, shininess, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -07001089}
1090
senorblanco5e5f9482014-08-26 12:27:12 -07001091SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
1092 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -07001093 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001094 fShininess(shininess)
1095{
1096}
1097
reed9fa60da2014-08-21 07:59:51 -07001098#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001099SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
reed9fa60da2014-08-21 07:59:51 -07001100 : INHERITED(buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001101{
1102 fKS = buffer.readScalar();
1103 fShininess = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001104 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001105 SkScalarIsFinite(fShininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001106}
reed9fa60da2014-08-21 07:59:51 -07001107#endif
1108
1109SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1110 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1111 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1112 SkScalar surfaceScale = buffer.readScalar();
1113 SkScalar ks = buffer.readScalar();
1114 SkScalar shine = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -07001115 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -07001116}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001117
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001118void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001119 this->INHERITED::flatten(buffer);
1120 buffer.writeScalar(fKS);
1121 buffer.writeScalar(fShininess);
1122}
1123
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001124bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1125 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001126 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001127 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001128 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001129 SkImageFilter* input = getInput(0);
1130 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001131 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001132 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001133 return false;
1134 }
1135
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001136 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001137 return false;
1138 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001139
1140 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001141 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001142 return false;
1143 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001144
1145 if (bounds.width() < 2 || bounds.height() < 2) {
1146 return false;
1147 }
1148
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001149 SkAutoLockPixels alp(src);
1150 if (!src.getPixels()) {
1151 return false;
1152 }
1153
reed84825042014-09-02 12:50:45 -07001154 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001155 return false;
1156 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001157
1158 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001159 offset->fX = bounds.left();
1160 offset->fY = bounds.top();
1161 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001162 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001163 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001164 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001165 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001166 break;
1167 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001168 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001169 break;
1170 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001171 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001172 break;
1173 }
1174 return true;
1175}
1176
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001177#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001178bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1179 GrTexture* texture,
1180 const SkMatrix& matrix,
1181 const SkIRect&) const {
1182 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001183 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001184 *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001185 }
1186 return true;
1187}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001188#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001189
1190///////////////////////////////////////////////////////////////////////////////
1191
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001192#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001193
1194namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001195SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001196 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1197 SkScalarToFloat(random->nextSScalar1()),
1198 SkScalarToFloat(random->nextSScalar1()));
1199}
1200
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001201SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001202 int type = random->nextULessThan(3);
1203 switch (type) {
1204 case 0: {
1205 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1206 }
1207 case 1: {
1208 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1209 }
1210 case 2: {
1211 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1212 random_point3(random),
1213 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001214 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001215 random->nextU()));
1216 }
1217 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001218 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001219 return NULL;
1220 }
1221}
1222
1223}
1224
joshualittb0a8a372014-09-23 09:50:21 -07001225class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001226public:
joshualittb0a8a372014-09-23 09:50:21 -07001227 GrGLLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001228 virtual ~GrGLLightingEffect();
1229
joshualitt15988992014-10-09 15:04:05 -07001230 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -07001231 const GrFragmentProcessor&,
1232 const GrProcessorKey&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001233 const char* outputColor,
1234 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001235 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001236 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001237
joshualittb0a8a372014-09-23 09:50:21 -07001238 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001239
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001240 /**
1241 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1242 */
joshualittb0a8a372014-09-23 09:50:21 -07001243 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001244
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001245protected:
joshualitt15988992014-10-09 15:04:05 -07001246 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001247
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248private:
joshualittb0a8a372014-09-23 09:50:21 -07001249 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001250
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001251 UniformHandle fImageIncrementUni;
1252 UniformHandle fSurfaceScaleUni;
1253 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001254};
1255
1256///////////////////////////////////////////////////////////////////////////////
1257
1258class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1259public:
joshualittb0a8a372014-09-23 09:50:21 -07001260 GrGLDiffuseLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
joshualitt15988992014-10-09 15:04:05 -07001261 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001262 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001263
1264private:
1265 typedef GrGLLightingEffect INHERITED;
1266
bsalomon@google.com032b2212012-07-16 13:36:18 +00001267 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001268};
1269
1270///////////////////////////////////////////////////////////////////////////////
1271
1272class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1273public:
joshualittb0a8a372014-09-23 09:50:21 -07001274 GrGLSpecularLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
joshualitt15988992014-10-09 15:04:05 -07001275 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001276 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001277
1278private:
1279 typedef GrGLLightingEffect INHERITED;
1280
bsalomon@google.com032b2212012-07-16 13:36:18 +00001281 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001282 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001283};
1284
1285///////////////////////////////////////////////////////////////////////////////
1286
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001287GrLightingEffect::GrLightingEffect(GrTexture* texture,
1288 const SkLight* light,
1289 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001290 const SkMatrix& matrix)
bsalomon6267f812014-08-29 15:05:53 -07001291 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001292 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001293 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001294 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001295 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001296 if (light->requiresFragmentPosition()) {
1297 this->setWillReadFragmentPosition();
1298 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001299}
1300
1301GrLightingEffect::~GrLightingEffect() {
1302 fLight->unref();
1303}
1304
bsalomon0e08fc12014-10-15 08:19:04 -07001305bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001306 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001307 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001308 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001309 fSurfaceScale == s.fSurfaceScale;
1310}
1311
1312///////////////////////////////////////////////////////////////////////////////
1313
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001314GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1315 const SkLight* light,
1316 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001317 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001318 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001319 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001320}
1321
joshualittb0a8a372014-09-23 09:50:21 -07001322const GrBackendFragmentProcessorFactory& GrDiffuseLightingEffect::getFactory() const {
1323 return GrTBackendFragmentProcessorFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001324}
1325
bsalomon0e08fc12014-10-15 08:19:04 -07001326bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001327 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001328 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001329 this->kd() == s.kd();
1330}
1331
joshualittb0a8a372014-09-23 09:50:21 -07001332GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001333
joshualittb0a8a372014-09-23 09:50:21 -07001334GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001335 GrContext* context,
1336 const GrDrawTargetCaps&,
1337 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001338 SkScalar surfaceScale = random->nextSScalar1();
1339 SkScalar kd = random->nextUScalar1();
1340 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001341 SkMatrix matrix;
1342 for (int i = 0; i < 9; i++) {
1343 matrix[i] = random->nextUScalar1();
1344 }
joshualittb0a8a372014-09-23 09:50:21 -07001345 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001346 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001347}
1348
1349
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001350///////////////////////////////////////////////////////////////////////////////
1351
joshualittb0a8a372014-09-23 09:50:21 -07001352GrGLLightingEffect::GrGLLightingEffect(const GrBackendProcessorFactory& factory,
1353 const GrProcessor& fp)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001354 : INHERITED(factory) {
joshualittb0a8a372014-09-23 09:50:21 -07001355 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001356 fLight = m.light()->createGLLight();
1357}
1358
1359GrGLLightingEffect::~GrGLLightingEffect() {
1360 delete fLight;
1361}
1362
joshualitt15988992014-10-09 15:04:05 -07001363void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001364 const GrFragmentProcessor&,
1365 const GrProcessorKey& key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001366 const char* outputColor,
1367 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001368 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001369 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001370 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001371 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001372 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001373 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001374 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001375 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001376 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001377 SkString lightFunc;
1378 this->emitLightFunc(builder, &lightFunc);
1379 static const GrGLShaderVar gSobelArgs[] = {
1380 GrGLShaderVar("a", kFloat_GrSLType),
1381 GrGLShaderVar("b", kFloat_GrSLType),
1382 GrGLShaderVar("c", kFloat_GrSLType),
1383 GrGLShaderVar("d", kFloat_GrSLType),
1384 GrGLShaderVar("e", kFloat_GrSLType),
1385 GrGLShaderVar("f", kFloat_GrSLType),
1386 GrGLShaderVar("scale", kFloat_GrSLType),
1387 };
1388 SkString sobelFuncName;
joshualitt15988992014-10-09 15:04:05 -07001389 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001390 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1391
1392 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001393 "sobel",
1394 SK_ARRAY_COUNT(gSobelArgs),
1395 gSobelArgs,
1396 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1397 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001398 static const GrGLShaderVar gPointToNormalArgs[] = {
1399 GrGLShaderVar("x", kFloat_GrSLType),
1400 GrGLShaderVar("y", kFloat_GrSLType),
1401 GrGLShaderVar("scale", kFloat_GrSLType),
1402 };
1403 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001404 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001405 "pointToNormal",
1406 SK_ARRAY_COUNT(gPointToNormalArgs),
1407 gPointToNormalArgs,
1408 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1409 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001410
1411 static const GrGLShaderVar gInteriorNormalArgs[] = {
1412 GrGLShaderVar("m", kFloat_GrSLType, 9),
1413 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1414 };
1415 SkString interiorNormalBody;
1416 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1417 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1418 "\t surfaceScale);\n",
1419 pointToNormalName.c_str(),
1420 sobelFuncName.c_str(),
1421 sobelFuncName.c_str());
1422 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001423 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001424 "interiorNormal",
1425 SK_ARRAY_COUNT(gInteriorNormalArgs),
1426 gInteriorNormalArgs,
1427 interiorNormalBody.c_str(),
1428 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001429
joshualitt30ba4362014-08-21 20:18:45 -07001430 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1431 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001432
1433 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1434 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1435
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001436 int index = 0;
1437 for (int dy = -1; dy <= 1; dy++) {
1438 for (int dx = -1; dx <= 1; dx++) {
1439 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001440 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001441 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1442 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1443 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001444 }
1445 }
joshualitt30ba4362014-08-21 20:18:45 -07001446 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001447 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001448 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001449 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001450 fsBuilder->codeAppend(";\n");
1451 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001452 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001453 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001454 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001455 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001456 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001457 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001458}
1459
joshualittb0a8a372014-09-23 09:50:21 -07001460void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1461 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
1462 b->add32(proc.cast<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001463}
1464
kkinnunen7510b222014-07-30 00:04:16 -07001465void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001466 const GrProcessor& proc) {
1467 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001468 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001469 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001470 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1471 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001472 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001473 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001474}
1475
1476///////////////////////////////////////////////////////////////////////////////
1477
1478///////////////////////////////////////////////////////////////////////////////
1479
joshualittb0a8a372014-09-23 09:50:21 -07001480GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendProcessorFactory& factory,
1481 const GrProcessor& proc)
1482 : INHERITED(factory, proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001483}
1484
joshualitt15988992014-10-09 15:04:05 -07001485void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001486 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001487 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001488 kFloat_GrSLType,
1489 "KD",
1490 &kd);
1491
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001492 static const GrGLShaderVar gLightArgs[] = {
1493 GrGLShaderVar("normal", kVec3f_GrSLType),
1494 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1495 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1496 };
1497 SkString lightBody;
1498 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1499 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001500 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1501 "light",
1502 SK_ARRAY_COUNT(gLightArgs),
1503 gLightArgs,
1504 lightBody.c_str(),
1505 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001506}
1507
kkinnunen7510b222014-07-30 00:04:16 -07001508void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001509 const GrProcessor& proc) {
1510 INHERITED::setData(pdman, proc);
1511 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001512 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001513}
1514
1515///////////////////////////////////////////////////////////////////////////////
1516
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001517GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1518 const SkLight* light,
1519 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001520 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001521 SkScalar ks,
1522 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001523 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001524 fKS(ks),
1525 fShininess(shininess) {
1526}
1527
joshualittb0a8a372014-09-23 09:50:21 -07001528const GrBackendFragmentProcessorFactory& GrSpecularLightingEffect::getFactory() const {
1529 return GrTBackendFragmentProcessorFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001530}
1531
bsalomon0e08fc12014-10-15 08:19:04 -07001532bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001533 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001534 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001535 this->ks() == s.ks() &&
1536 this->shininess() == s.shininess();
1537}
1538
joshualittb0a8a372014-09-23 09:50:21 -07001539GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001540
joshualittb0a8a372014-09-23 09:50:21 -07001541GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1542 GrContext* context,
1543 const GrDrawTargetCaps&,
1544 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001545 SkScalar surfaceScale = random->nextSScalar1();
1546 SkScalar ks = random->nextUScalar1();
1547 SkScalar shininess = random->nextUScalar1();
1548 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001549 SkMatrix matrix;
1550 for (int i = 0; i < 9; i++) {
1551 matrix[i] = random->nextUScalar1();
1552 }
joshualittb0a8a372014-09-23 09:50:21 -07001553 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001554 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001555}
1556
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001557///////////////////////////////////////////////////////////////////////////////
1558
joshualittb0a8a372014-09-23 09:50:21 -07001559GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendProcessorFactory& factory,
1560 const GrProcessor& proc)
1561 : INHERITED(factory, proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001562}
1563
joshualitt15988992014-10-09 15:04:05 -07001564void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001565 const char* ks;
1566 const char* shininess;
1567
joshualitt30ba4362014-08-21 20:18:45 -07001568 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001569 kFloat_GrSLType, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001570 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001571 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001572
1573 static const GrGLShaderVar gLightArgs[] = {
1574 GrGLShaderVar("normal", kVec3f_GrSLType),
1575 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1576 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1577 };
1578 SkString lightBody;
1579 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1580 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001581 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1582 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001583 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1584 "light",
1585 SK_ARRAY_COUNT(gLightArgs),
1586 gLightArgs,
1587 lightBody.c_str(),
1588 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001589}
1590
kkinnunen7510b222014-07-30 00:04:16 -07001591void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001592 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001593 INHERITED::setData(pdman, effect);
1594 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001595 pdman.set1f(fKSUni, spec.ks());
1596 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001597}
1598
1599///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001600void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001601 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001602 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001603}
1604
joshualitt15988992014-10-09 15:04:05 -07001605void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001606 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001607 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001608}
1609
kkinnunen7510b222014-07-30 00:04:16 -07001610void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001611 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001612 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001613}
1614
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001615///////////////////////////////////////////////////////////////////////////////
1616
kkinnunen7510b222014-07-30 00:04:16 -07001617void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001618 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001619 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001620 SkASSERT(light->type() == SkLight::kDistant_LightType);
1621 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001622 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001623}
1624
joshualitt15988992014-10-09 15:04:05 -07001625void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001626 const char* dir;
joshualitt30ba4362014-08-21 20:18:45 -07001627 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001628 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001629 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001630}
1631
1632///////////////////////////////////////////////////////////////////////////////
1633
kkinnunen7510b222014-07-30 00:04:16 -07001634void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001635 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001636 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001637 SkASSERT(light->type() == SkLight::kPoint_LightType);
1638 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001639 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001640}
1641
joshualitt15988992014-10-09 15:04:05 -07001642void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001643 const char* loc;
joshualitt30ba4362014-08-21 20:18:45 -07001644 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001645 "LightLocation", &loc);
joshualitt15988992014-10-09 15:04:05 -07001646 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001647 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1648 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001649}
1650
1651///////////////////////////////////////////////////////////////////////////////
1652
kkinnunen7510b222014-07-30 00:04:16 -07001653void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001654 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001655 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001656 SkASSERT(light->type() == SkLight::kSpot_LightType);
1657 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001658 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1659 pdman.set1f(fExponentUni, spotLight->specularExponent());
1660 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1661 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1662 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1663 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001664}
1665
joshualitt15988992014-10-09 15:04:05 -07001666void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001667 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001668 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001669 kVec3f_GrSLType, "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001670
joshualitt15988992014-10-09 15:04:05 -07001671 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001672 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1673 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001674}
1675
joshualitt15988992014-10-09 15:04:05 -07001676void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001677 const char *surfaceToLight) {
1678
1679 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1680
1681 const char* exponent;
1682 const char* cosInner;
1683 const char* cosOuter;
1684 const char* coneScale;
1685 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001686 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001687 kFloat_GrSLType, "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001688 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001689 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001690 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001691 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001692 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001693 kFloat_GrSLType, "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001694 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001695 kVec3f_GrSLType, "S", &s);
1696
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001697 static const GrGLShaderVar gLightColorArgs[] = {
1698 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1699 };
1700 SkString lightColorBody;
1701 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1702 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1703 lightColorBody.appendf("\t\treturn vec3(0);\n");
1704 lightColorBody.appendf("\t}\n");
1705 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1706 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1707 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1708 color, cosOuter, coneScale);
1709 lightColorBody.appendf("\t}\n");
1710 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt15988992014-10-09 15:04:05 -07001711 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001712 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001713 "lightColor",
1714 SK_ARRAY_COUNT(gLightColorArgs),
1715 gLightColorArgs,
1716 lightColorBody.c_str(),
1717 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001718
joshualitt30ba4362014-08-21 20:18:45 -07001719 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001720}
1721
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001722#endif
1723
djsollen@google.com08337772012-06-26 14:33:13 +00001724SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1725 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1726 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001727SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END