blob: ce787c6ab823da291e4df0caa83d3cd5be459805 [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:
joshualittb0a8a372014-09-23 09:50:21 -0700354 virtual bool onIsEqual(const GrProcessor&) 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.
358 inout->fValidFlags = 0;
359 inout->fIsSingleComponent = false;
360 }
361
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000362private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000363 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000364 const SkLight* fLight;
365 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000366 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000367};
368
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000369class GrDiffuseLightingEffect : public GrLightingEffect {
370public:
joshualittb0a8a372014-09-23 09:50:21 -0700371 static GrFragmentProcessor* Create(GrTexture* texture,
372 const SkLight* light,
373 SkScalar surfaceScale,
374 const SkMatrix& matrix,
375 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700376 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
377 light,
378 surfaceScale,
379 matrix,
380 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000381 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000382
383 static const char* Name() { return "DiffuseLighting"; }
384
joshualittb0a8a372014-09-23 09:50:21 -0700385 typedef GrGLDiffuseLightingEffect GLProcessor;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000386
joshualittb0a8a372014-09-23 09:50:21 -0700387 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000388 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000389
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000390private:
joshualittb0a8a372014-09-23 09:50:21 -0700391 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000392
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000393 GrDiffuseLightingEffect(GrTexture* texture,
394 const SkLight* light,
395 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000396 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000397 SkScalar kd);
398
joshualittb0a8a372014-09-23 09:50:21 -0700399 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000400 typedef GrLightingEffect INHERITED;
401 SkScalar fKD;
402};
403
404class GrSpecularLightingEffect : public GrLightingEffect {
405public:
joshualittb0a8a372014-09-23 09:50:21 -0700406 static GrFragmentProcessor* Create(GrTexture* texture,
407 const SkLight* light,
408 SkScalar surfaceScale,
409 const SkMatrix& matrix,
410 SkScalar ks,
411 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700412 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
413 light,
414 surfaceScale,
415 matrix,
416 ks,
417 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000418 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000419 static const char* Name() { return "SpecularLighting"; }
420
joshualittb0a8a372014-09-23 09:50:21 -0700421 typedef GrGLSpecularLightingEffect GLProcessor;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000422
joshualittb0a8a372014-09-23 09:50:21 -0700423 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000424 SkScalar ks() const { return fKS; }
425 SkScalar shininess() const { return fShininess; }
426
427private:
joshualittb0a8a372014-09-23 09:50:21 -0700428 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000429
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000430 GrSpecularLightingEffect(GrTexture* texture,
431 const SkLight* light,
432 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000433 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000434 SkScalar ks,
435 SkScalar shininess);
436
joshualittb0a8a372014-09-23 09:50:21 -0700437 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000438 typedef GrLightingEffect INHERITED;
439 SkScalar fKS;
440 SkScalar fShininess;
441};
442
443///////////////////////////////////////////////////////////////////////////////
444
445class GrGLLight {
446public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000447 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000448
449 /**
450 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
451 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
452 */
joshualitt30ba4362014-08-21 20:18:45 -0700453 void emitLightColorUniform(GrGLProgramBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000454
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000455 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000456 * These two functions are called from GrGLLightingEffect's emitCode() function.
457 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
458 * the light. The expression will be used in the FS. emitLightColor writes an expression into
459 * the FS that is the color of the light. Either function may add functions and/or uniforms to
460 * the FS. The default of emitLightColor appends the name of the constant light color uniform
461 * and so this function only needs to be overridden if the light color varies spatially.
462 */
joshualitt30ba4362014-08-21 20:18:45 -0700463 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) = 0;
464 virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000465
466 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
467 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700468 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000469 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000470
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000471protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000472 /**
473 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
474 * function.
475 */
476 UniformHandle lightColorUni() const { return fColorUni; }
477
478private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000479 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000480
481 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000482};
483
484///////////////////////////////////////////////////////////////////////////////
485
486class GrGLDistantLight : public GrGLLight {
487public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000488 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700489 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000490 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700491 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000492
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493private:
494 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496};
497
498///////////////////////////////////////////////////////////////////////////////
499
500class GrGLPointLight : public GrGLLight {
501public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000502 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700503 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000504 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700505 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000506
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000507private:
508 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000509 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510};
511
512///////////////////////////////////////////////////////////////////////////////
513
514class GrGLSpotLight : public GrGLLight {
515public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000516 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700517 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000518 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700519 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
520 virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000521
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000522private:
523 typedef GrGLLight INHERITED;
524
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000525 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000526 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000527 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000528 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000529 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000530 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000531 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000532};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000533#else
534
535class GrGLLight;
536
537#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000538
539};
540
541///////////////////////////////////////////////////////////////////////////////
542
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000543class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000544public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000545 SK_DECLARE_INST_COUNT(SkLight)
546
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000547 enum LightType {
548 kDistant_LightType,
549 kPoint_LightType,
550 kSpot_LightType,
551 };
552 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000553 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000554 virtual GrGLLight* createGLLight() const = 0;
555 virtual bool isEqual(const SkLight& other) const {
556 return fColor == other.fColor;
557 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000558 // Called to know whether the generated GrGLLight will require access to the fragment position.
559 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000560 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000561
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000562 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000563 void flattenLight(SkWriteBuffer& buffer) const;
564 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000565
djsollen@google.com08337772012-06-26 14:33:13 +0000566protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000567 SkLight(SkColor color)
568 : fColor(SkIntToScalar(SkColorGetR(color)),
569 SkIntToScalar(SkColorGetG(color)),
570 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000571 SkLight(const SkPoint3& color)
572 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000573 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000574 fColor = readPoint3(buffer);
575 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000576
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000577 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000578
djsollen@google.com08337772012-06-26 14:33:13 +0000579
580private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000581 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000582 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000583};
584
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000585///////////////////////////////////////////////////////////////////////////////
586
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587class SkDistantLight : public SkLight {
588public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000589 SkDistantLight(const SkPoint3& direction, SkColor color)
590 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591 }
djsollen@google.com08337772012-06-26 14:33:13 +0000592
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000593 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
594 return fDirection;
595 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000596 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000597 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000598 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000599 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
600#if SK_SUPPORT_GPU
601 return SkNEW(GrGLDistantLight);
602#else
603 SkDEBUGFAIL("Should not call in GPU-less build");
604 return NULL;
605#endif
606 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000607 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
608
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000609 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
610 if (other.type() != kDistant_LightType) {
611 return false;
612 }
613
614 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
615 return INHERITED::isEqual(other) &&
616 fDirection == o.fDirection;
617 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000619 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000620 fDirection = readPoint3(buffer);
621 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000622
djsollen@google.com08337772012-06-26 14:33:13 +0000623protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000624 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
625 : INHERITED(color), fDirection(direction) {
626 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000627 virtual SkLight* transform(const SkMatrix& matrix) const {
628 return new SkDistantLight(direction(), color());
629 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000630 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000631 writePoint3(fDirection, buffer);
632 }
633
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000634private:
djsollen@google.com08337772012-06-26 14:33:13 +0000635 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000636 SkPoint3 fDirection;
637};
638
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000639///////////////////////////////////////////////////////////////////////////////
640
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000641class SkPointLight : public SkLight {
642public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000643 SkPointLight(const SkPoint3& location, SkColor color)
644 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000645
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000646 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
647 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
648 fLocation.fY - SkIntToScalar(y),
649 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
650 direction.normalize();
651 return direction;
652 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000653 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000654 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000655 const SkPoint3& location() const { return fLocation; }
656 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000657#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000658 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000659#else
660 SkDEBUGFAIL("Should not call in GPU-less build");
661 return NULL;
662#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000663 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000664 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000665 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000666 if (other.type() != kPoint_LightType) {
667 return false;
668 }
669 const SkPointLight& o = static_cast<const SkPointLight&>(other);
670 return INHERITED::isEqual(other) &&
671 fLocation == o.fLocation;
672 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000673 virtual SkLight* transform(const SkMatrix& matrix) const {
674 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
675 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000676 // Use X scale and Y scale on Z and average the result
677 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
678 matrix.mapVectors(&locationZ, 1);
679 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000680 return new SkPointLight(location, color());
681 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000682
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000683 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000684 fLocation = readPoint3(buffer);
685 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000686
687protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000688 SkPointLight(const SkPoint3& location, const SkPoint3& color)
689 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000690 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000691 writePoint3(fLocation, buffer);
692 }
693
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000694private:
djsollen@google.com08337772012-06-26 14:33:13 +0000695 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696 SkPoint3 fLocation;
697};
698
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000699///////////////////////////////////////////////////////////////////////////////
700
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701class SkSpotLight : public SkLight {
702public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000703 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
704 : INHERITED(color),
705 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000706 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000707 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000708 {
709 fS = target - location;
710 fS.normalize();
711 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000712 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000713 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
714 fConeScale = SkScalarInvert(antiAliasThreshold);
715 }
djsollen@google.com08337772012-06-26 14:33:13 +0000716
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000717 virtual SkLight* transform(const SkMatrix& matrix) const {
718 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
719 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000720 // Use X scale and Y scale on Z and average the result
721 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
722 matrix.mapVectors(&locationZ, 1);
723 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000724 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
725 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000726 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
727 matrix.mapVectors(&targetZ, 1);
728 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
729 SkPoint3 s = target - location;
730 s.normalize();
731 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000732 }
733
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000734 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
735 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
736 fLocation.fY - SkIntToScalar(y),
737 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
738 direction.normalize();
739 return direction;
740 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000742 SkScalar cosAngle = -surfaceToLight.dot(fS);
743 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000744 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000745 }
746 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
747 if (cosAngle < fCosInnerConeAngle) {
748 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000749 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000750 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000751 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000752 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000753 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000754#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000755 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000756#else
757 SkDEBUGFAIL("Should not call in GPU-less build");
758 return NULL;
759#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000760 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000761 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000762 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000763 const SkPoint3& location() const { return fLocation; }
764 const SkPoint3& target() const { return fTarget; }
765 SkScalar specularExponent() const { return fSpecularExponent; }
766 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
767 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
768 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000769 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000770
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000771 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000772 fLocation = readPoint3(buffer);
773 fTarget = readPoint3(buffer);
774 fSpecularExponent = buffer.readScalar();
775 fCosOuterConeAngle = buffer.readScalar();
776 fCosInnerConeAngle = buffer.readScalar();
777 fConeScale = buffer.readScalar();
778 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000779 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
780 SkScalarIsFinite(fCosOuterConeAngle) &&
781 SkScalarIsFinite(fCosInnerConeAngle) &&
782 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000783 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000784protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000785 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
786 : INHERITED(color),
787 fLocation(location),
788 fTarget(target),
789 fSpecularExponent(specularExponent),
790 fCosOuterConeAngle(cosOuterConeAngle),
791 fCosInnerConeAngle(cosInnerConeAngle),
792 fConeScale(coneScale),
793 fS(s)
794 {
795 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000796 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000797 writePoint3(fLocation, buffer);
798 writePoint3(fTarget, buffer);
799 buffer.writeScalar(fSpecularExponent);
800 buffer.writeScalar(fCosOuterConeAngle);
801 buffer.writeScalar(fCosInnerConeAngle);
802 buffer.writeScalar(fConeScale);
803 writePoint3(fS, buffer);
804 }
805
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000806 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000807 if (other.type() != kSpot_LightType) {
808 return false;
809 }
810
811 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
812 return INHERITED::isEqual(other) &&
813 fLocation == o.fLocation &&
814 fTarget == o.fTarget &&
815 fSpecularExponent == o.fSpecularExponent &&
816 fCosOuterConeAngle == o.fCosOuterConeAngle;
817 }
818
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000819private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000820 static const SkScalar kSpecularExponentMin;
821 static const SkScalar kSpecularExponentMax;
822
djsollen@google.com08337772012-06-26 14:33:13 +0000823 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000824 SkPoint3 fLocation;
825 SkPoint3 fTarget;
826 SkScalar fSpecularExponent;
827 SkScalar fCosOuterConeAngle;
828 SkScalar fCosInnerConeAngle;
829 SkScalar fConeScale;
830 SkPoint3 fS;
831};
832
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000833// According to the spec, the specular term should be in the range [1, 128] :
834// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000835const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
836const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000837
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000838///////////////////////////////////////////////////////////////////////////////
839
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000840void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000841 // Write type first, then baseclass, then subclass.
842 buffer.writeInt(this->type());
843 writePoint3(fColor, buffer);
844 this->onFlattenLight(buffer);
845}
846
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000847/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000848 // Read type first.
849 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
850 switch (type) {
851 // Each of these constructors must first call SkLight's, so we'll read the baseclass
852 // then subclass, same order as flattenLight.
853 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
854 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
855 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
856 default:
857 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000858 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000859 return NULL;
860 }
861}
862///////////////////////////////////////////////////////////////////////////////
863
senorblanco9ea3d572014-07-08 09:16:22 -0700864SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700865 SkImageFilter* input, const CropRect* cropRect,
866 uint32_t uniqueID)
867 : INHERITED(1, &input, cropRect, uniqueID)
reed9fa60da2014-08-21 07:59:51 -0700868 , fLight(SkRef(light))
869 , fSurfaceScale(surfaceScale / 255)
870{}
871
872SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
873 SkColor lightColor,
874 SkScalar surfaceScale,
875 SkScalar kd,
876 SkImageFilter* input,
877 const CropRect* cropRect) {
878 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
879 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000880}
881
reed9fa60da2014-08-21 07:59:51 -0700882SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
883 SkColor lightColor,
884 SkScalar surfaceScale,
885 SkScalar kd,
886 SkImageFilter* input,
887 const CropRect* cropRect) {
888 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
889 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000890}
891
reed9fa60da2014-08-21 07:59:51 -0700892SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
893 const SkPoint3& target,
894 SkScalar specularExponent,
895 SkScalar cutoffAngle,
896 SkColor lightColor,
897 SkScalar surfaceScale,
898 SkScalar kd,
899 SkImageFilter* input,
900 const CropRect* cropRect) {
901 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
902 cutoffAngle, lightColor)));
903 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904}
905
reed9fa60da2014-08-21 07:59:51 -0700906SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
907 SkColor lightColor,
908 SkScalar surfaceScale,
909 SkScalar ks,
910 SkScalar shine,
911 SkImageFilter* input,
912 const CropRect* cropRect) {
913 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
914 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000915}
916
reed9fa60da2014-08-21 07:59:51 -0700917SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
918 SkColor lightColor,
919 SkScalar surfaceScale,
920 SkScalar ks,
921 SkScalar shine,
922 SkImageFilter* input,
923 const CropRect* cropRect) {
924 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
925 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000926}
927
reed9fa60da2014-08-21 07:59:51 -0700928SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
929 const SkPoint3& target,
930 SkScalar specularExponent,
931 SkScalar cutoffAngle,
932 SkColor lightColor,
933 SkScalar surfaceScale,
934 SkScalar ks,
935 SkScalar shine,
936 SkImageFilter* input,
937 const CropRect* cropRect) {
938 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
939 cutoffAngle, lightColor)));
940 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000941}
942
reed9fa60da2014-08-21 07:59:51 -0700943SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000944
reed9fa60da2014-08-21 07:59:51 -0700945#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000946SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000947 : INHERITED(1, buffer) {
reed9fa60da2014-08-21 07:59:51 -0700948 fLight.reset(SkLight::UnflattenLight(buffer));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000949 fSurfaceScale = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000950 buffer.validate(SkScalarIsFinite(fSurfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000951}
reed9fa60da2014-08-21 07:59:51 -0700952#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000953
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000954void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000955 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000956 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700957 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000958}
959
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000960///////////////////////////////////////////////////////////////////////////////
961
reed9fa60da2014-08-21 07:59:51 -0700962SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700963 SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -0700964 if (NULL == light) {
965 return NULL;
966 }
967 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
968 return NULL;
969 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000970 // According to the spec, kd can be any non-negative number :
971 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700972 if (kd < 0) {
973 return NULL;
974 }
senorblanco5e5f9482014-08-26 12:27:12 -0700975 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -0700976}
977
senorblanco5e5f9482014-08-26 12:27:12 -0700978SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
979 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -0700980 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000981{
982}
983
reed9fa60da2014-08-21 07:59:51 -0700984#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000985SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000986 : INHERITED(buffer)
987{
988 fKD = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000989 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000990}
reed9fa60da2014-08-21 07:59:51 -0700991#endif
992
993SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
994 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
995 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
996 SkScalar surfaceScale = buffer.readScalar();
997 SkScalar kd = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -0700998 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -0700999}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001000
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001001void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001002 this->INHERITED::flatten(buffer);
1003 buffer.writeScalar(fKD);
1004}
1005
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001006bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1007 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001008 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001009 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001010 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001011 SkImageFilter* input = getInput(0);
1012 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001013 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001014 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001015 return false;
1016 }
1017
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001018 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001019 return false;
1020 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001021 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001022 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001023 return false;
1024 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001025
1026 if (bounds.width() < 2 || bounds.height() < 2) {
1027 return false;
1028 }
1029
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001030 SkAutoLockPixels alp(src);
1031 if (!src.getPixels()) {
1032 return false;
1033 }
1034
reed84825042014-09-02 12:50:45 -07001035 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001036 return false;
1037 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001038
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001039 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001040
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001041 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001042 offset->fX = bounds.left();
1043 offset->fY = bounds.top();
1044 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001045 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001046 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001047 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001048 break;
1049 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001050 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001051 break;
1052 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001053 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001054 break;
1055 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001056
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001057 return true;
1058}
1059
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001060#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001061bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1062 GrTexture* texture,
1063 const SkMatrix& matrix,
1064 const SkIRect&) const {
1065 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001066 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001067 *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001068 }
1069 return true;
1070}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001071#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001072
1073///////////////////////////////////////////////////////////////////////////////
1074
reed9fa60da2014-08-21 07:59:51 -07001075SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -07001076 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -07001077 if (NULL == light) {
1078 return NULL;
1079 }
1080 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1081 return NULL;
1082 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001083 // According to the spec, ks can be any non-negative number :
1084 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001085 if (ks < 0) {
1086 return NULL;
1087 }
1088 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco5e5f9482014-08-26 12:27:12 -07001089 (light, surfaceScale, ks, shininess, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -07001090}
1091
senorblanco5e5f9482014-08-26 12:27:12 -07001092SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
1093 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -07001094 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001095 fShininess(shininess)
1096{
1097}
1098
reed9fa60da2014-08-21 07:59:51 -07001099#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001100SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
reed9fa60da2014-08-21 07:59:51 -07001101 : INHERITED(buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001102{
1103 fKS = buffer.readScalar();
1104 fShininess = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001105 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001106 SkScalarIsFinite(fShininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001107}
reed9fa60da2014-08-21 07:59:51 -07001108#endif
1109
1110SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1111 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1112 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1113 SkScalar surfaceScale = buffer.readScalar();
1114 SkScalar ks = buffer.readScalar();
1115 SkScalar shine = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -07001116 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -07001117}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001118
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001119void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001120 this->INHERITED::flatten(buffer);
1121 buffer.writeScalar(fKS);
1122 buffer.writeScalar(fShininess);
1123}
1124
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001125bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1126 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001127 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001128 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001129 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001130 SkImageFilter* input = getInput(0);
1131 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001132 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001133 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001134 return false;
1135 }
1136
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001137 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001138 return false;
1139 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001140
1141 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001142 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001143 return false;
1144 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001145
1146 if (bounds.width() < 2 || bounds.height() < 2) {
1147 return false;
1148 }
1149
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001150 SkAutoLockPixels alp(src);
1151 if (!src.getPixels()) {
1152 return false;
1153 }
1154
reed84825042014-09-02 12:50:45 -07001155 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001156 return false;
1157 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001158
1159 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001160 offset->fX = bounds.left();
1161 offset->fY = bounds.top();
1162 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001163 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001164 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001165 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001166 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001167 break;
1168 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001169 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170 break;
1171 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001172 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001173 break;
1174 }
1175 return true;
1176}
1177
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001178#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001179bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1180 GrTexture* texture,
1181 const SkMatrix& matrix,
1182 const SkIRect&) const {
1183 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001184 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001185 *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001186 }
1187 return true;
1188}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001189#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001190
1191///////////////////////////////////////////////////////////////////////////////
1192
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001193#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001194
1195namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001196SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001197 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1198 SkScalarToFloat(random->nextSScalar1()),
1199 SkScalarToFloat(random->nextSScalar1()));
1200}
1201
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001202SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001203 int type = random->nextULessThan(3);
1204 switch (type) {
1205 case 0: {
1206 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1207 }
1208 case 1: {
1209 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1210 }
1211 case 2: {
1212 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1213 random_point3(random),
1214 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001215 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001216 random->nextU()));
1217 }
1218 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001219 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001220 return NULL;
1221 }
1222}
1223
1224}
1225
joshualittb0a8a372014-09-23 09:50:21 -07001226class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001227public:
joshualittb0a8a372014-09-23 09:50:21 -07001228 GrGLLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229 virtual ~GrGLLightingEffect();
1230
joshualitt30ba4362014-08-21 20:18:45 -07001231 virtual void emitCode(GrGLProgramBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -07001232 const GrFragmentProcessor&,
1233 const GrProcessorKey&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001234 const char* outputColor,
1235 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001236 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001237 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001238
joshualittb0a8a372014-09-23 09:50:21 -07001239 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001240
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001241 /**
1242 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1243 */
joshualittb0a8a372014-09-23 09:50:21 -07001244 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001245
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001246protected:
joshualitt30ba4362014-08-21 20:18:45 -07001247 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001248
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001249private:
joshualittb0a8a372014-09-23 09:50:21 -07001250 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001251
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001252 UniformHandle fImageIncrementUni;
1253 UniformHandle fSurfaceScaleUni;
1254 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001255};
1256
1257///////////////////////////////////////////////////////////////////////////////
1258
1259class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1260public:
joshualittb0a8a372014-09-23 09:50:21 -07001261 GrGLDiffuseLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
joshualitt30ba4362014-08-21 20:18:45 -07001262 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001263 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001264
1265private:
1266 typedef GrGLLightingEffect INHERITED;
1267
bsalomon@google.com032b2212012-07-16 13:36:18 +00001268 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001269};
1270
1271///////////////////////////////////////////////////////////////////////////////
1272
1273class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1274public:
joshualittb0a8a372014-09-23 09:50:21 -07001275 GrGLSpecularLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
joshualitt30ba4362014-08-21 20:18:45 -07001276 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
joshualittb0a8a372014-09-23 09:50:21 -07001277 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001278
1279private:
1280 typedef GrGLLightingEffect INHERITED;
1281
bsalomon@google.com032b2212012-07-16 13:36:18 +00001282 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001283 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001284};
1285
1286///////////////////////////////////////////////////////////////////////////////
1287
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001288GrLightingEffect::GrLightingEffect(GrTexture* texture,
1289 const SkLight* light,
1290 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001291 const SkMatrix& matrix)
bsalomon6267f812014-08-29 15:05:53 -07001292 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001293 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001294 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001295 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001296 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001297 if (light->requiresFragmentPosition()) {
1298 this->setWillReadFragmentPosition();
1299 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001300}
1301
1302GrLightingEffect::~GrLightingEffect() {
1303 fLight->unref();
1304}
1305
joshualittb0a8a372014-09-23 09:50:21 -07001306bool GrLightingEffect::onIsEqual(const GrProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001307 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001308 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001309 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001310 fSurfaceScale == s.fSurfaceScale;
1311}
1312
1313///////////////////////////////////////////////////////////////////////////////
1314
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001315GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1316 const SkLight* light,
1317 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001318 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001319 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001320 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001321}
1322
joshualittb0a8a372014-09-23 09:50:21 -07001323const GrBackendFragmentProcessorFactory& GrDiffuseLightingEffect::getFactory() const {
1324 return GrTBackendFragmentProcessorFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001325}
1326
joshualittb0a8a372014-09-23 09:50:21 -07001327bool GrDiffuseLightingEffect::onIsEqual(const GrProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001328 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001329 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001330 this->kd() == s.kd();
1331}
1332
joshualittb0a8a372014-09-23 09:50:21 -07001333GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001334
joshualittb0a8a372014-09-23 09:50:21 -07001335GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001336 GrContext* context,
1337 const GrDrawTargetCaps&,
1338 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001339 SkScalar surfaceScale = random->nextSScalar1();
1340 SkScalar kd = random->nextUScalar1();
1341 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001342 SkMatrix matrix;
1343 for (int i = 0; i < 9; i++) {
1344 matrix[i] = random->nextUScalar1();
1345 }
joshualittb0a8a372014-09-23 09:50:21 -07001346 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001347 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001348}
1349
1350
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001351///////////////////////////////////////////////////////////////////////////////
1352
joshualittb0a8a372014-09-23 09:50:21 -07001353GrGLLightingEffect::GrGLLightingEffect(const GrBackendProcessorFactory& factory,
1354 const GrProcessor& fp)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001355 : INHERITED(factory) {
joshualittb0a8a372014-09-23 09:50:21 -07001356 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001357 fLight = m.light()->createGLLight();
1358}
1359
1360GrGLLightingEffect::~GrGLLightingEffect() {
1361 delete fLight;
1362}
1363
joshualitt30ba4362014-08-21 20:18:45 -07001364void GrGLLightingEffect::emitCode(GrGLProgramBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001365 const GrFragmentProcessor&,
1366 const GrProcessorKey& key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001367 const char* outputColor,
1368 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001369 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001370 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001371 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001372 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001373 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001374 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001375 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001376 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001377 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001378 SkString lightFunc;
1379 this->emitLightFunc(builder, &lightFunc);
1380 static const GrGLShaderVar gSobelArgs[] = {
1381 GrGLShaderVar("a", kFloat_GrSLType),
1382 GrGLShaderVar("b", kFloat_GrSLType),
1383 GrGLShaderVar("c", kFloat_GrSLType),
1384 GrGLShaderVar("d", kFloat_GrSLType),
1385 GrGLShaderVar("e", kFloat_GrSLType),
1386 GrGLShaderVar("f", kFloat_GrSLType),
1387 GrGLShaderVar("scale", kFloat_GrSLType),
1388 };
1389 SkString sobelFuncName;
joshualitt30ba4362014-08-21 20:18:45 -07001390 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1391 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1392
1393 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001394 "sobel",
1395 SK_ARRAY_COUNT(gSobelArgs),
1396 gSobelArgs,
1397 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1398 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001399 static const GrGLShaderVar gPointToNormalArgs[] = {
1400 GrGLShaderVar("x", kFloat_GrSLType),
1401 GrGLShaderVar("y", kFloat_GrSLType),
1402 GrGLShaderVar("scale", kFloat_GrSLType),
1403 };
1404 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001405 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001406 "pointToNormal",
1407 SK_ARRAY_COUNT(gPointToNormalArgs),
1408 gPointToNormalArgs,
1409 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1410 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001411
1412 static const GrGLShaderVar gInteriorNormalArgs[] = {
1413 GrGLShaderVar("m", kFloat_GrSLType, 9),
1414 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1415 };
1416 SkString interiorNormalBody;
1417 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1418 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1419 "\t surfaceScale);\n",
1420 pointToNormalName.c_str(),
1421 sobelFuncName.c_str(),
1422 sobelFuncName.c_str());
1423 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001424 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001425 "interiorNormal",
1426 SK_ARRAY_COUNT(gInteriorNormalArgs),
1427 gInteriorNormalArgs,
1428 interiorNormalBody.c_str(),
1429 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001430
joshualitt30ba4362014-08-21 20:18:45 -07001431 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1432 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001433
1434 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1435 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1436
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001437 int index = 0;
1438 for (int dy = -1; dy <= 1; dy++) {
1439 for (int dx = -1; dx <= 1; dx++) {
1440 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001441 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001442 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1443 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1444 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001445 }
1446 }
joshualitt30ba4362014-08-21 20:18:45 -07001447 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001448 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001449 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001450 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001451 fsBuilder->codeAppend(";\n");
1452 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001453 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001454 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001455 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001456 SkString modulate;
1457 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001458 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001459}
1460
joshualittb0a8a372014-09-23 09:50:21 -07001461void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1462 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
1463 b->add32(proc.cast<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001464}
1465
kkinnunen7510b222014-07-30 00:04:16 -07001466void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001467 const GrProcessor& proc) {
1468 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001469 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001470 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001471 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1472 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001473 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001474 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001475}
1476
1477///////////////////////////////////////////////////////////////////////////////
1478
1479///////////////////////////////////////////////////////////////////////////////
1480
joshualittb0a8a372014-09-23 09:50:21 -07001481GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendProcessorFactory& factory,
1482 const GrProcessor& proc)
1483 : INHERITED(factory, proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001484}
1485
joshualitt30ba4362014-08-21 20:18:45 -07001486void GrGLDiffuseLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001487 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001488 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001489 kFloat_GrSLType,
1490 "KD",
1491 &kd);
1492
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001493 static const GrGLShaderVar gLightArgs[] = {
1494 GrGLShaderVar("normal", kVec3f_GrSLType),
1495 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1496 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1497 };
1498 SkString lightBody;
1499 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1500 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001501 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1502 "light",
1503 SK_ARRAY_COUNT(gLightArgs),
1504 gLightArgs,
1505 lightBody.c_str(),
1506 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001507}
1508
kkinnunen7510b222014-07-30 00:04:16 -07001509void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001510 const GrProcessor& proc) {
1511 INHERITED::setData(pdman, proc);
1512 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001513 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001514}
1515
1516///////////////////////////////////////////////////////////////////////////////
1517
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001518GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1519 const SkLight* light,
1520 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001521 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001522 SkScalar ks,
1523 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001524 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525 fKS(ks),
1526 fShininess(shininess) {
1527}
1528
joshualittb0a8a372014-09-23 09:50:21 -07001529const GrBackendFragmentProcessorFactory& GrSpecularLightingEffect::getFactory() const {
1530 return GrTBackendFragmentProcessorFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001531}
1532
joshualittb0a8a372014-09-23 09:50:21 -07001533bool GrSpecularLightingEffect::onIsEqual(const GrProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001534 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001535 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001536 this->ks() == s.ks() &&
1537 this->shininess() == s.shininess();
1538}
1539
joshualittb0a8a372014-09-23 09:50:21 -07001540GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001541
joshualittb0a8a372014-09-23 09:50:21 -07001542GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1543 GrContext* context,
1544 const GrDrawTargetCaps&,
1545 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001546 SkScalar surfaceScale = random->nextSScalar1();
1547 SkScalar ks = random->nextUScalar1();
1548 SkScalar shininess = random->nextUScalar1();
1549 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001550 SkMatrix matrix;
1551 for (int i = 0; i < 9; i++) {
1552 matrix[i] = random->nextUScalar1();
1553 }
joshualittb0a8a372014-09-23 09:50:21 -07001554 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001555 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001556}
1557
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001558///////////////////////////////////////////////////////////////////////////////
1559
joshualittb0a8a372014-09-23 09:50:21 -07001560GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendProcessorFactory& factory,
1561 const GrProcessor& proc)
1562 : INHERITED(factory, proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001563}
1564
joshualitt30ba4362014-08-21 20:18:45 -07001565void GrGLSpecularLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001566 const char* ks;
1567 const char* shininess;
1568
joshualitt30ba4362014-08-21 20:18:45 -07001569 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001570 kFloat_GrSLType, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001571 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001572 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001573
1574 static const GrGLShaderVar gLightArgs[] = {
1575 GrGLShaderVar("normal", kVec3f_GrSLType),
1576 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1577 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1578 };
1579 SkString lightBody;
1580 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1581 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001582 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1583 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001584 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1585 "light",
1586 SK_ARRAY_COUNT(gLightArgs),
1587 gLightArgs,
1588 lightBody.c_str(),
1589 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001590}
1591
kkinnunen7510b222014-07-30 00:04:16 -07001592void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001593 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001594 INHERITED::setData(pdman, effect);
1595 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001596 pdman.set1f(fKSUni, spec.ks());
1597 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001598}
1599
1600///////////////////////////////////////////////////////////////////////////////
joshualitt30ba4362014-08-21 20:18:45 -07001601void GrGLLight::emitLightColorUniform(GrGLProgramBuilder* builder) {
1602 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001603 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001604}
1605
joshualitt30ba4362014-08-21 20:18:45 -07001606void GrGLLight::emitLightColor(GrGLProgramBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001607 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001608 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001609}
1610
kkinnunen7510b222014-07-30 00:04:16 -07001611void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001612 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001613 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001614}
1615
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001616///////////////////////////////////////////////////////////////////////////////
1617
kkinnunen7510b222014-07-30 00:04:16 -07001618void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001619 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001620 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001621 SkASSERT(light->type() == SkLight::kDistant_LightType);
1622 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001623 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001624}
1625
joshualitt30ba4362014-08-21 20:18:45 -07001626void GrGLDistantLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001627 const char* dir;
joshualitt30ba4362014-08-21 20:18:45 -07001628 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001629 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001630 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001631}
1632
1633///////////////////////////////////////////////////////////////////////////////
1634
kkinnunen7510b222014-07-30 00:04:16 -07001635void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001636 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001637 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638 SkASSERT(light->type() == SkLight::kPoint_LightType);
1639 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001640 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001641}
1642
joshualitt30ba4362014-08-21 20:18:45 -07001643void GrGLPointLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001644 const char* loc;
joshualitt30ba4362014-08-21 20:18:45 -07001645 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001646 "LightLocation", &loc);
joshualitt30ba4362014-08-21 20:18:45 -07001647 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1648 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1649 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001650}
1651
1652///////////////////////////////////////////////////////////////////////////////
1653
kkinnunen7510b222014-07-30 00:04:16 -07001654void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001655 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001656 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001657 SkASSERT(light->type() == SkLight::kSpot_LightType);
1658 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001659 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1660 pdman.set1f(fExponentUni, spotLight->specularExponent());
1661 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1662 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1663 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1664 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001665}
1666
joshualitt30ba4362014-08-21 20:18:45 -07001667void GrGLSpotLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001668 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001669 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001670 kVec3f_GrSLType, "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001671
1672 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1673 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1674 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001675}
1676
joshualitt30ba4362014-08-21 20:18:45 -07001677void GrGLSpotLight::emitLightColor(GrGLProgramBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001678 const char *surfaceToLight) {
1679
1680 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1681
1682 const char* exponent;
1683 const char* cosInner;
1684 const char* cosOuter;
1685 const char* coneScale;
1686 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001687 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001688 kFloat_GrSLType, "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001689 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001690 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001691 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001692 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001693 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001694 kFloat_GrSLType, "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001695 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001696 kVec3f_GrSLType, "S", &s);
1697
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001698 static const GrGLShaderVar gLightColorArgs[] = {
1699 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1700 };
1701 SkString lightColorBody;
1702 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1703 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1704 lightColorBody.appendf("\t\treturn vec3(0);\n");
1705 lightColorBody.appendf("\t}\n");
1706 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1707 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1708 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1709 color, cosOuter, coneScale);
1710 lightColorBody.appendf("\t}\n");
1711 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt30ba4362014-08-21 20:18:45 -07001712 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1713 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001714 "lightColor",
1715 SK_ARRAY_COUNT(gLightColorArgs),
1716 gLightColorArgs,
1717 lightColorBody.c_str(),
1718 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001719
joshualitt30ba4362014-08-21 20:18:45 -07001720 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001721}
1722
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001723#endif
1724
djsollen@google.com08337772012-06-26 14:33:13 +00001725SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1726 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1727 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001728SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END