blob: 682f2bad56c51c7c9a112c5f8d4f8903df866b7c [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"
bsalomon@google.comd698f772012-10-25 13:22:00 +000019#include "gl/GrGLEffect.h"
bsalomon848faf02014-07-11 10:01:02 -070020#include "gl/GrGLShaderBuilder.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000021#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000022#include "GrTBackendEffectFactory.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
28typedef GrGLUniformManager::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
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000039void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000040 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
commit-bot@chromium.orgd3baf202013-11-07 22:06:08 +000041 uman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000042}
43
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000044void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000045 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000046}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000047#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000048
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000049// Shift matrix components to the left, as we advance pixels to the right.
50inline void shiftMatrixLeft(int m[9]) {
51 m[0] = m[1];
52 m[3] = m[4];
53 m[6] = m[7];
54 m[1] = m[2];
55 m[4] = m[5];
56 m[7] = m[8];
57}
58
59class DiffuseLightingType {
60public:
61 DiffuseLightingType(SkScalar kd)
62 : fKD(kd) {}
63 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
64 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
65 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
66 SkPoint3 color(lightColor * colorScale);
67 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000068 SkClampMax(SkScalarRoundToInt(color.fX), 255),
69 SkClampMax(SkScalarRoundToInt(color.fY), 255),
70 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000071 }
72private:
73 SkScalar fKD;
74};
75
76class SpecularLightingType {
77public:
78 SpecularLightingType(SkScalar ks, SkScalar shininess)
79 : fKS(ks), fShininess(shininess) {}
80 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
81 SkPoint3 halfDir(surfaceTolight);
82 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
83 halfDir.normalize();
84 SkScalar colorScale = SkScalarMul(fKS,
85 SkScalarPow(normal.dot(halfDir), fShininess));
86 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
87 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000088 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
89 SkClampMax(SkScalarRoundToInt(color.fX), 255),
90 SkClampMax(SkScalarRoundToInt(color.fY), 255),
91 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000092 }
93private:
94 SkScalar fKS;
95 SkScalar fShininess;
96};
97
98inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
99 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
100}
101
102inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
103 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
104 SkScalarMul(-y, surfaceScale),
105 SK_Scalar1);
106 vector.normalize();
107 return vector;
108}
109
110inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
111 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
112 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
113 surfaceScale);
114}
115
116inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
117 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
118 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
119 surfaceScale);
120}
121
122inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
123 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
124 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
125 surfaceScale);
126}
127
128inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
129 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
130 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
131 surfaceScale);
132}
133
134
135inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
137 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
138 surfaceScale);
139}
140
141inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
142 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
143 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
144 surfaceScale);
145}
146
147inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
148 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
149 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
150 surfaceScale);
151}
152
153inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
154 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
155 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
156 surfaceScale);
157}
158
159inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
160 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
161 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
162 surfaceScale);
163}
164
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000165template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
166 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000167 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000168 int left = bounds.left(), right = bounds.right();
169 int bottom = bounds.bottom();
170 int y = bounds.top();
171 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000172 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000173 int x = left;
174 const SkPMColor* row1 = src.getAddr32(x, y);
175 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000176 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000177 m[4] = SkGetPackedA32(*row1++);
178 m[5] = SkGetPackedA32(*row1++);
179 m[7] = SkGetPackedA32(*row2++);
180 m[8] = SkGetPackedA32(*row2++);
181 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000182 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000183 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000184 {
185 shiftMatrixLeft(m);
186 m[5] = SkGetPackedA32(*row1++);
187 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000188 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000189 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000190 }
191 shiftMatrixLeft(m);
192 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000193 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000194 }
195
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000196 for (++y; y < bottom - 1; ++y) {
197 int x = left;
198 const SkPMColor* row0 = src.getAddr32(x, y - 1);
199 const SkPMColor* row1 = src.getAddr32(x, y);
200 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000201 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000202 m[1] = SkGetPackedA32(*row0++);
203 m[2] = SkGetPackedA32(*row0++);
204 m[4] = SkGetPackedA32(*row1++);
205 m[5] = SkGetPackedA32(*row1++);
206 m[7] = SkGetPackedA32(*row2++);
207 m[8] = SkGetPackedA32(*row2++);
208 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000209 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000210 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000211 shiftMatrixLeft(m);
212 m[2] = SkGetPackedA32(*row0++);
213 m[5] = SkGetPackedA32(*row1++);
214 m[8] = SkGetPackedA32(*row2++);
215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000216 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000217 }
218 shiftMatrixLeft(m);
219 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000220 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 }
222
223 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000224 int x = left;
225 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
226 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000227 int m[9];
228 m[1] = SkGetPackedA32(*row0++);
229 m[2] = SkGetPackedA32(*row0++);
230 m[4] = SkGetPackedA32(*row1++);
231 m[5] = SkGetPackedA32(*row1++);
232 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000233 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000234 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000235 {
236 shiftMatrixLeft(m);
237 m[2] = SkGetPackedA32(*row0++);
238 m[5] = SkGetPackedA32(*row1++);
239 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000240 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000241 }
242 shiftMatrixLeft(m);
243 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000244 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000245 }
246}
247
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000248SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000249 SkPoint3 point;
250 point.fX = buffer.readScalar();
251 point.fY = buffer.readScalar();
252 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000253 buffer.validate(SkScalarIsFinite(point.fX) &&
254 SkScalarIsFinite(point.fY) &&
255 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000256 return point;
257};
258
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000259void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000260 buffer.writeScalar(point.fX);
261 buffer.writeScalar(point.fY);
262 buffer.writeScalar(point.fZ);
263};
264
265class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
266public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000267 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000268 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000269 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000270 SkScalar kd() const { return fKD; }
271
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000272protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000273 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
274 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000275 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000276 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000277#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700278 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
279 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000280#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000281
282private:
283 typedef SkLightingImageFilter INHERITED;
284 SkScalar fKD;
285};
286
287class SkSpecularLightingImageFilter : public SkLightingImageFilter {
288public:
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000289 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
291
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000292 SkScalar ks() const { return fKS; }
293 SkScalar shininess() const { return fShininess; }
294
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000295protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000296 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
297 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000298 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000299 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000300#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700301 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
302 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000303#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000304
305private:
306 typedef SkLightingImageFilter INHERITED;
307 SkScalar fKS;
308 SkScalar fShininess;
309};
310
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000311#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000312
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000313class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000314public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000315 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000316 virtual ~GrLightingEffect();
317
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000318 const SkLight* light() const { return fLight; }
319 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000320 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000321
322 virtual void getConstantColorComponents(GrColor* color,
323 uint32_t* validFlags) const SK_OVERRIDE {
324 // lighting shaders are complicated. We just throw up our hands.
325 *validFlags = 0;
326 }
327
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000328protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000329 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000330
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000331private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000332 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000333 const SkLight* fLight;
334 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000335 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000336};
337
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000338class GrDiffuseLightingEffect : public GrLightingEffect {
339public:
bsalomon83d081a2014-07-08 09:56:10 -0700340 static GrEffect* Create(GrTexture* texture,
341 const SkLight* light,
342 SkScalar surfaceScale,
343 const SkMatrix& matrix,
344 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700345 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
346 light,
347 surfaceScale,
348 matrix,
349 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000350 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000351
352 static const char* Name() { return "DiffuseLighting"; }
353
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000354 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000355
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000356 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000357 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000358
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000359private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000360 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000361
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000362 GrDiffuseLightingEffect(GrTexture* texture,
363 const SkLight* light,
364 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000365 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000366 SkScalar kd);
367
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000368 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000369 typedef GrLightingEffect INHERITED;
370 SkScalar fKD;
371};
372
373class GrSpecularLightingEffect : public GrLightingEffect {
374public:
bsalomon83d081a2014-07-08 09:56:10 -0700375 static GrEffect* Create(GrTexture* texture,
376 const SkLight* light,
377 SkScalar surfaceScale,
378 const SkMatrix& matrix,
379 SkScalar ks,
380 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700381 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
382 light,
383 surfaceScale,
384 matrix,
385 ks,
386 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000387 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000388 static const char* Name() { return "SpecularLighting"; }
389
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000390 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000391
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000392 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000393 SkScalar ks() const { return fKS; }
394 SkScalar shininess() const { return fShininess; }
395
396private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000397 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000398
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000399 GrSpecularLightingEffect(GrTexture* texture,
400 const SkLight* light,
401 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000402 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000403 SkScalar ks,
404 SkScalar shininess);
405
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000406 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000407 typedef GrLightingEffect INHERITED;
408 SkScalar fKS;
409 SkScalar fShininess;
410};
411
412///////////////////////////////////////////////////////////////////////////////
413
414class GrGLLight {
415public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000416 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000417
418 /**
419 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
420 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
421 */
422 void emitLightColorUniform(GrGLShaderBuilder*);
423
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000424 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000425 * These two functions are called from GrGLLightingEffect's emitCode() function.
426 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
427 * the light. The expression will be used in the FS. emitLightColor writes an expression into
428 * the FS that is the color of the light. Either function may add functions and/or uniforms to
429 * the FS. The default of emitLightColor appends the name of the constant light color uniform
430 * and so this function only needs to be overridden if the light color varies spatially.
431 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000432 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000433 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
434
435 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
436 // INHERITED::setData().
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000437 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000438 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000439
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000440protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000441 /**
442 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
443 * function.
444 */
445 UniformHandle lightColorUni() const { return fColorUni; }
446
447private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000448 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000449
450 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000451};
452
453///////////////////////////////////////////////////////////////////////////////
454
455class GrGLDistantLight : public GrGLLight {
456public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000457 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000458 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000459 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000460 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000461
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000462private:
463 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000464 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000465};
466
467///////////////////////////////////////////////////////////////////////////////
468
469class GrGLPointLight : public GrGLLight {
470public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000471 virtual ~GrGLPointLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000472 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000473 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000474 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000475
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000476private:
477 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000478 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000479};
480
481///////////////////////////////////////////////////////////////////////////////
482
483class GrGLSpotLight : public GrGLLight {
484public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000485 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000486 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000487 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000488 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000489 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000490
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491private:
492 typedef GrGLLight INHERITED;
493
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000494 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000496 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000497 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000498 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000499 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000500 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000501};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000502#else
503
504class GrGLLight;
505
506#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000507
508};
509
510///////////////////////////////////////////////////////////////////////////////
511
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000512class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000513public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000514 SK_DECLARE_INST_COUNT(SkLight)
515
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000516 enum LightType {
517 kDistant_LightType,
518 kPoint_LightType,
519 kSpot_LightType,
520 };
521 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000522 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000523 virtual GrGLLight* createGLLight() const = 0;
524 virtual bool isEqual(const SkLight& other) const {
525 return fColor == other.fColor;
526 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000527 // Called to know whether the generated GrGLLight will require access to the fragment position.
528 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000529 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000530
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000531 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000532 void flattenLight(SkWriteBuffer& buffer) const;
533 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000534
djsollen@google.com08337772012-06-26 14:33:13 +0000535protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000536 SkLight(SkColor color)
537 : fColor(SkIntToScalar(SkColorGetR(color)),
538 SkIntToScalar(SkColorGetG(color)),
539 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000540 SkLight(const SkPoint3& color)
541 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000542 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000543 fColor = readPoint3(buffer);
544 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000545
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000546 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000547
djsollen@google.com08337772012-06-26 14:33:13 +0000548
549private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000550 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000551 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000552};
553
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000554///////////////////////////////////////////////////////////////////////////////
555
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000556class SkDistantLight : public SkLight {
557public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000558 SkDistantLight(const SkPoint3& direction, SkColor color)
559 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560 }
djsollen@google.com08337772012-06-26 14:33:13 +0000561
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000562 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
563 return fDirection;
564 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000565 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000566 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000568 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
569#if SK_SUPPORT_GPU
570 return SkNEW(GrGLDistantLight);
571#else
572 SkDEBUGFAIL("Should not call in GPU-less build");
573 return NULL;
574#endif
575 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000576 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
577
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000578 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
579 if (other.type() != kDistant_LightType) {
580 return false;
581 }
582
583 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
584 return INHERITED::isEqual(other) &&
585 fDirection == o.fDirection;
586 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000588 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000589 fDirection = readPoint3(buffer);
590 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591
djsollen@google.com08337772012-06-26 14:33:13 +0000592protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000593 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
594 : INHERITED(color), fDirection(direction) {
595 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000596 virtual SkLight* transform(const SkMatrix& matrix) const {
597 return new SkDistantLight(direction(), color());
598 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000599 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000600 writePoint3(fDirection, buffer);
601 }
602
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000603private:
djsollen@google.com08337772012-06-26 14:33:13 +0000604 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000605 SkPoint3 fDirection;
606};
607
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000608///////////////////////////////////////////////////////////////////////////////
609
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000610class SkPointLight : public SkLight {
611public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000612 SkPointLight(const SkPoint3& location, SkColor color)
613 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000614
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000615 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
616 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
617 fLocation.fY - SkIntToScalar(y),
618 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
619 direction.normalize();
620 return direction;
621 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000622 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000623 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000624 const SkPoint3& location() const { return fLocation; }
625 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000626#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000627 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000628#else
629 SkDEBUGFAIL("Should not call in GPU-less build");
630 return NULL;
631#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000633 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000634 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000635 if (other.type() != kPoint_LightType) {
636 return false;
637 }
638 const SkPointLight& o = static_cast<const SkPointLight&>(other);
639 return INHERITED::isEqual(other) &&
640 fLocation == o.fLocation;
641 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000642 virtual SkLight* transform(const SkMatrix& matrix) const {
643 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
644 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000645 // Use X scale and Y scale on Z and average the result
646 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
647 matrix.mapVectors(&locationZ, 1);
648 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000649 return new SkPointLight(location, color());
650 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000651
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000652 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000653 fLocation = readPoint3(buffer);
654 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000655
656protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000657 SkPointLight(const SkPoint3& location, const SkPoint3& color)
658 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000659 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000660 writePoint3(fLocation, buffer);
661 }
662
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000663private:
djsollen@google.com08337772012-06-26 14:33:13 +0000664 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000665 SkPoint3 fLocation;
666};
667
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000668///////////////////////////////////////////////////////////////////////////////
669
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000670class SkSpotLight : public SkLight {
671public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000672 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
673 : INHERITED(color),
674 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000675 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000676 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000677 {
678 fS = target - location;
679 fS.normalize();
680 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000681 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000682 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
683 fConeScale = SkScalarInvert(antiAliasThreshold);
684 }
djsollen@google.com08337772012-06-26 14:33:13 +0000685
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000686 virtual SkLight* transform(const SkMatrix& matrix) const {
687 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
688 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000689 // Use X scale and Y scale on Z and average the result
690 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
691 matrix.mapVectors(&locationZ, 1);
692 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000693 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
694 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000695 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
696 matrix.mapVectors(&targetZ, 1);
697 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
698 SkPoint3 s = target - location;
699 s.normalize();
700 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000701 }
702
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
704 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
705 fLocation.fY - SkIntToScalar(y),
706 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
707 direction.normalize();
708 return direction;
709 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000710 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711 SkScalar cosAngle = -surfaceToLight.dot(fS);
712 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000713 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000714 }
715 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
716 if (cosAngle < fCosInnerConeAngle) {
717 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000718 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000719 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000720 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000721 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000722 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000723#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000724 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000725#else
726 SkDEBUGFAIL("Should not call in GPU-less build");
727 return NULL;
728#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000729 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000730 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000731 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000732 const SkPoint3& location() const { return fLocation; }
733 const SkPoint3& target() const { return fTarget; }
734 SkScalar specularExponent() const { return fSpecularExponent; }
735 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
736 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
737 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000738 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000739
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000740 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000741 fLocation = readPoint3(buffer);
742 fTarget = readPoint3(buffer);
743 fSpecularExponent = buffer.readScalar();
744 fCosOuterConeAngle = buffer.readScalar();
745 fCosInnerConeAngle = buffer.readScalar();
746 fConeScale = buffer.readScalar();
747 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000748 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
749 SkScalarIsFinite(fCosOuterConeAngle) &&
750 SkScalarIsFinite(fCosInnerConeAngle) &&
751 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000752 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000753protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000754 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
755 : INHERITED(color),
756 fLocation(location),
757 fTarget(target),
758 fSpecularExponent(specularExponent),
759 fCosOuterConeAngle(cosOuterConeAngle),
760 fCosInnerConeAngle(cosInnerConeAngle),
761 fConeScale(coneScale),
762 fS(s)
763 {
764 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000765 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000766 writePoint3(fLocation, buffer);
767 writePoint3(fTarget, buffer);
768 buffer.writeScalar(fSpecularExponent);
769 buffer.writeScalar(fCosOuterConeAngle);
770 buffer.writeScalar(fCosInnerConeAngle);
771 buffer.writeScalar(fConeScale);
772 writePoint3(fS, buffer);
773 }
774
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000775 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000776 if (other.type() != kSpot_LightType) {
777 return false;
778 }
779
780 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
781 return INHERITED::isEqual(other) &&
782 fLocation == o.fLocation &&
783 fTarget == o.fTarget &&
784 fSpecularExponent == o.fSpecularExponent &&
785 fCosOuterConeAngle == o.fCosOuterConeAngle;
786 }
787
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000788private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000789 static const SkScalar kSpecularExponentMin;
790 static const SkScalar kSpecularExponentMax;
791
djsollen@google.com08337772012-06-26 14:33:13 +0000792 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000793 SkPoint3 fLocation;
794 SkPoint3 fTarget;
795 SkScalar fSpecularExponent;
796 SkScalar fCosOuterConeAngle;
797 SkScalar fCosInnerConeAngle;
798 SkScalar fConeScale;
799 SkPoint3 fS;
800};
801
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000802// According to the spec, the specular term should be in the range [1, 128] :
803// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000804const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
805const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000806
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000807///////////////////////////////////////////////////////////////////////////////
808
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000809void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000810 // Write type first, then baseclass, then subclass.
811 buffer.writeInt(this->type());
812 writePoint3(fColor, buffer);
813 this->onFlattenLight(buffer);
814}
815
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000816/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000817 // Read type first.
818 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
819 switch (type) {
820 // Each of these constructors must first call SkLight's, so we'll read the baseclass
821 // then subclass, same order as flattenLight.
822 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
823 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
824 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
825 default:
826 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000827 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000828 return NULL;
829 }
830}
831///////////////////////////////////////////////////////////////////////////////
832
senorblanco9ea3d572014-07-08 09:16:22 -0700833SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
834 SkImageFilter* input, const CropRect* cropRect)
835 : INHERITED(1, &input, cropRect),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000836 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000837 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
838{
839 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000840 // our caller knows that we take ownership of the light, so we don't
841 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000842}
843
844SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000845 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000846 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000847 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000848 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000849 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850}
851
852SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000853 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000854 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000855 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000856 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000857 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000858}
859
860SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000861 const SkPoint3& location, const SkPoint3& target,
862 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000863 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000864 SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000865 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000866 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
867 cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000868 surfaceScale, kd, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000869}
870
871SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000872 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000873 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000874 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000875 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000876 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000877}
878
879SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000880 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000881 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000882 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000883 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000884 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000885}
886
887SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000888 const SkPoint3& location, const SkPoint3& target,
889 SkScalar specularExponent, SkScalar cutoffAngle,
890 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000891 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000892 return SkNEW_ARGS(SkSpecularLightingImageFilter,
893 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000894 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000895}
896
897SkLightingImageFilter::~SkLightingImageFilter() {
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000898 SkSafeUnref(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000899}
900
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000901SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000902 : INHERITED(1, buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000903 fLight = SkLight::UnflattenLight(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904 fSurfaceScale = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000905 buffer.validate(SkScalarIsFinite(fSurfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000906}
907
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000908void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000909 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000910 fLight->flattenLight(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 buffer.writeScalar(fSurfaceScale);
912}
913
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000914///////////////////////////////////////////////////////////////////////////////
915
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000916SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000917 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000918 // According to the spec, kd can be any non-negative number :
919 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
920 fKD(kd < 0 ? 0 : kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000921{
922}
923
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000924SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000925 : INHERITED(buffer)
926{
927 fKD = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000928 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000929}
930
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000931void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000932 this->INHERITED::flatten(buffer);
933 buffer.writeScalar(fKD);
934}
935
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000936bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
937 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000938 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000939 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000940 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000941 SkImageFilter* input = getInput(0);
942 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000943 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000944 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000945 return false;
946 }
947
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000948 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000949 return false;
950 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000951 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000952 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000953 return false;
954 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000955
956 if (bounds.width() < 2 || bounds.height() < 2) {
957 return false;
958 }
959
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000960 SkAutoLockPixels alp(src);
961 if (!src.getPixels()) {
962 return false;
963 }
964
reedc77392e2014-06-02 13:07:26 -0700965 if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000966 return false;
967 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000968
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000969 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000970
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000971 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000972 offset->fX = bounds.left();
973 offset->fY = bounds.top();
974 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000975 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000976 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000977 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000978 break;
979 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000980 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000981 break;
982 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000983 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000984 break;
985 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000986
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000987 return true;
988}
989
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000990#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700991bool SkDiffuseLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
992 const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000993 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000994 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000995 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000996 }
997 return true;
998}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000999#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000
1001///////////////////////////////////////////////////////////////////////////////
1002
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +00001003SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001004 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001005 // According to the spec, ks can be any non-negative number :
1006 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
1007 fKS(ks < 0 ? 0 : ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001008 fShininess(shininess)
1009{
1010}
1011
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001012SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001013 : INHERITED(buffer)
1014{
1015 fKS = buffer.readScalar();
1016 fShininess = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001017 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001018 SkScalarIsFinite(fShininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001019}
1020
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001021void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001022 this->INHERITED::flatten(buffer);
1023 buffer.writeScalar(fKS);
1024 buffer.writeScalar(fShininess);
1025}
1026
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001027bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1028 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001029 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001030 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001031 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001032 SkImageFilter* input = getInput(0);
1033 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001034 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001035 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001036 return false;
1037 }
1038
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001039 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001040 return false;
1041 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001042
1043 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001044 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001045 return false;
1046 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001047
1048 if (bounds.width() < 2 || bounds.height() < 2) {
1049 return false;
1050 }
1051
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001052 SkAutoLockPixels alp(src);
1053 if (!src.getPixels()) {
1054 return false;
1055 }
1056
reedc77392e2014-06-02 13:07:26 -07001057 if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001058 return false;
1059 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001060
1061 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001062 offset->fX = bounds.left();
1063 offset->fY = bounds.top();
1064 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001065 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001066 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001067 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001068 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001069 break;
1070 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001071 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001072 break;
1073 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001074 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001075 break;
1076 }
1077 return true;
1078}
1079
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001080#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -07001081bool SkSpecularLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
1082 const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001083 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001084 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001085 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001086 }
1087 return true;
1088}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001089#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001090
1091///////////////////////////////////////////////////////////////////////////////
1092
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001093#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001094
1095namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001096SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001097 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1098 SkScalarToFloat(random->nextSScalar1()),
1099 SkScalarToFloat(random->nextSScalar1()));
1100}
1101
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001102SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001103 int type = random->nextULessThan(3);
1104 switch (type) {
1105 case 0: {
1106 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1107 }
1108 case 1: {
1109 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1110 }
1111 case 2: {
1112 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1113 random_point3(random),
1114 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001115 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001116 random->nextU()));
1117 }
1118 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001119 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001120 return NULL;
1121 }
1122}
1123
1124}
1125
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001126class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001127public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001128 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001129 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001130 virtual ~GrGLLightingEffect();
1131
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001132 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001133 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001134 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001135 const char* outputColor,
1136 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001137 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001138 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001139
bsalomon@google.comc7818882013-03-20 19:19:53 +00001140 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001141
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001142 /**
1143 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1144 */
bsalomon@google.comc7818882013-03-20 19:19:53 +00001145 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001146
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001147protected:
1148 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1149
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001150private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001151 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001152
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001153 UniformHandle fImageIncrementUni;
1154 UniformHandle fSurfaceScaleUni;
1155 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001156};
1157
1158///////////////////////////////////////////////////////////////////////////////
1159
1160class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1161public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001162 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001163 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001164 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001165 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001166
1167private:
1168 typedef GrGLLightingEffect INHERITED;
1169
bsalomon@google.com032b2212012-07-16 13:36:18 +00001170 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001171};
1172
1173///////////////////////////////////////////////////////////////////////////////
1174
1175class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1176public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001177 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001178 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001179 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001180 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001181
1182private:
1183 typedef GrGLLightingEffect INHERITED;
1184
bsalomon@google.com032b2212012-07-16 13:36:18 +00001185 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001186 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001187};
1188
1189///////////////////////////////////////////////////////////////////////////////
1190
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001191GrLightingEffect::GrLightingEffect(GrTexture* texture,
1192 const SkLight* light,
1193 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001194 const SkMatrix& matrix)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001195 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001196 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001197 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001198 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001199 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001200 if (light->requiresFragmentPosition()) {
1201 this->setWillReadFragmentPosition();
1202 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001203}
1204
1205GrLightingEffect::~GrLightingEffect() {
1206 fLight->unref();
1207}
1208
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001209bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001210 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001211 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001212 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001213 fSurfaceScale == s.fSurfaceScale;
1214}
1215
1216///////////////////////////////////////////////////////////////////////////////
1217
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001218GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1219 const SkLight* light,
1220 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001221 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001222 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001223 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001224}
1225
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001226const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1227 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001228}
1229
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001230bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001231 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001232 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001233 this->kd() == s.kd();
1234}
1235
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001236GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001237
bsalomon83d081a2014-07-08 09:56:10 -07001238GrEffect* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1239 GrContext* context,
1240 const GrDrawTargetCaps&,
1241 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001242 SkScalar surfaceScale = random->nextSScalar1();
1243 SkScalar kd = random->nextUScalar1();
1244 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001245 SkMatrix matrix;
1246 for (int i = 0; i < 9; i++) {
1247 matrix[i] = random->nextUScalar1();
1248 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001249 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001250 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001251}
1252
1253
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001254///////////////////////////////////////////////////////////////////////////////
1255
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001256GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001257 const GrDrawEffect& drawEffect)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001258 : INHERITED(factory) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001259 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001260 fLight = m.light()->createGLLight();
1261}
1262
1263GrGLLightingEffect::~GrGLLightingEffect() {
1264 delete fLight;
1265}
1266
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001267void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001268 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001269 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001270 const char* outputColor,
1271 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001272 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001273 const TextureSamplerArray& samplers) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001274 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001275
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001276 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001277 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001278 "ImageIncrement");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001279 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001280 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001281 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001282 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001283 SkString lightFunc;
1284 this->emitLightFunc(builder, &lightFunc);
1285 static const GrGLShaderVar gSobelArgs[] = {
1286 GrGLShaderVar("a", kFloat_GrSLType),
1287 GrGLShaderVar("b", kFloat_GrSLType),
1288 GrGLShaderVar("c", kFloat_GrSLType),
1289 GrGLShaderVar("d", kFloat_GrSLType),
1290 GrGLShaderVar("e", kFloat_GrSLType),
1291 GrGLShaderVar("f", kFloat_GrSLType),
1292 GrGLShaderVar("scale", kFloat_GrSLType),
1293 };
1294 SkString sobelFuncName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001295 builder->fsEmitFunction(kFloat_GrSLType,
1296 "sobel",
1297 SK_ARRAY_COUNT(gSobelArgs),
1298 gSobelArgs,
1299 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1300 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001301 static const GrGLShaderVar gPointToNormalArgs[] = {
1302 GrGLShaderVar("x", kFloat_GrSLType),
1303 GrGLShaderVar("y", kFloat_GrSLType),
1304 GrGLShaderVar("scale", kFloat_GrSLType),
1305 };
1306 SkString pointToNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001307 builder->fsEmitFunction(kVec3f_GrSLType,
1308 "pointToNormal",
1309 SK_ARRAY_COUNT(gPointToNormalArgs),
1310 gPointToNormalArgs,
1311 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1312 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001313
1314 static const GrGLShaderVar gInteriorNormalArgs[] = {
1315 GrGLShaderVar("m", kFloat_GrSLType, 9),
1316 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1317 };
1318 SkString interiorNormalBody;
1319 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1320 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1321 "\t surfaceScale);\n",
1322 pointToNormalName.c_str(),
1323 sobelFuncName.c_str(),
1324 sobelFuncName.c_str());
1325 SkString interiorNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001326 builder->fsEmitFunction(kVec3f_GrSLType,
1327 "interiorNormal",
1328 SK_ARRAY_COUNT(gInteriorNormalArgs),
1329 gInteriorNormalArgs,
1330 interiorNormalBody.c_str(),
1331 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001332
bsalomon@google.com77af6802013-10-02 13:04:56 +00001333 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001334 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001335
1336 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1337 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1338
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001339 int index = 0;
1340 for (int dy = -1; dy <= 1; dy++) {
1341 for (int dx = -1; dx <= 1; dx++) {
1342 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001343 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001344 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001345 builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001346 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001347 }
1348 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001349 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001350 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001351 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001352 fLight->emitSurfaceToLight(builder, arg.c_str());
1353 builder->fsCodeAppend(";\n");
1354 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1355 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001356 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001357 builder->fsCodeAppend(");\n");
1358 SkString modulate;
1359 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1360 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001361}
1362
bsalomon@google.comc7818882013-03-20 19:19:53 +00001363GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001364 const GrGLCaps& caps) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001365 return drawEffect.castEffect<GrLightingEffect>().light()->type();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001366}
1367
bsalomon@google.comc7818882013-03-20 19:19:53 +00001368void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1369 const GrDrawEffect& drawEffect) {
1370 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1371 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001372 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001373 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001374 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001375 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1376 fLight->setData(uman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001377}
1378
1379///////////////////////////////////////////////////////////////////////////////
1380
1381///////////////////////////////////////////////////////////////////////////////
1382
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001383GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001384 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001385 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001386}
1387
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001388void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001389 const char* kd;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001390 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001391 kFloat_GrSLType,
1392 "KD",
1393 &kd);
1394
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001395 static const GrGLShaderVar gLightArgs[] = {
1396 GrGLShaderVar("normal", kVec3f_GrSLType),
1397 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1398 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1399 };
1400 SkString lightBody;
1401 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1402 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001403 builder->fsEmitFunction(kVec4f_GrSLType,
1404 "light",
1405 SK_ARRAY_COUNT(gLightArgs),
1406 gLightArgs,
1407 lightBody.c_str(),
1408 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001409}
1410
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001411void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001412 const GrDrawEffect& drawEffect) {
1413 INHERITED::setData(uman, drawEffect);
1414 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1415 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001416}
1417
1418///////////////////////////////////////////////////////////////////////////////
1419
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001420GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1421 const SkLight* light,
1422 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001423 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001424 SkScalar ks,
1425 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001426 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001427 fKS(ks),
1428 fShininess(shininess) {
1429}
1430
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001431const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1432 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001433}
1434
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001435bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001436 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001437 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001438 this->ks() == s.ks() &&
1439 this->shininess() == s.shininess();
1440}
1441
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001442GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001443
bsalomon83d081a2014-07-08 09:56:10 -07001444GrEffect* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1445 GrContext* context,
1446 const GrDrawTargetCaps&,
1447 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001448 SkScalar surfaceScale = random->nextSScalar1();
1449 SkScalar ks = random->nextUScalar1();
1450 SkScalar shininess = random->nextUScalar1();
1451 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001452 SkMatrix matrix;
1453 for (int i = 0; i < 9; i++) {
1454 matrix[i] = random->nextUScalar1();
1455 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001456 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001457 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001458}
1459
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001460///////////////////////////////////////////////////////////////////////////////
1461
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001462GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001463 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001464 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001465}
1466
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001467void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001468 const char* ks;
1469 const char* shininess;
1470
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001471 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001472 kFloat_GrSLType, "KS", &ks);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001473 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001474 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001475
1476 static const GrGLShaderVar gLightArgs[] = {
1477 GrGLShaderVar("normal", kVec3f_GrSLType),
1478 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1479 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1480 };
1481 SkString lightBody;
1482 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1483 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001484 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1485 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001486 builder->fsEmitFunction(kVec4f_GrSLType,
1487 "light",
1488 SK_ARRAY_COUNT(gLightArgs),
1489 gLightArgs,
1490 lightBody.c_str(),
1491 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001492}
1493
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001494void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001495 const GrDrawEffect& drawEffect) {
1496 INHERITED::setData(uman, drawEffect);
1497 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1498 uman.set1f(fKSUni, spec.ks());
1499 uman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001500}
1501
1502///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001503void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001504 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001505 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001506}
1507
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001508void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1509 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001510 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001511}
1512
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001513void GrGLLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001514 const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001515 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001516}
1517
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518///////////////////////////////////////////////////////////////////////////////
1519
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001520void GrGLDistantLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001521 const SkLight* light) const {
1522 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001523 SkASSERT(light->type() == SkLight::kDistant_LightType);
1524 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001525 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001526}
1527
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001528void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001529 const char* dir;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001530 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001531 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001532 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001533}
1534
1535///////////////////////////////////////////////////////////////////////////////
1536
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001537void GrGLPointLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001538 const SkLight* light) const {
1539 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001540 SkASSERT(light->type() == SkLight::kPoint_LightType);
1541 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001542 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001543}
1544
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001545void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001546 const char* loc;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001547 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001548 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001549 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001550}
1551
1552///////////////////////////////////////////////////////////////////////////////
1553
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001554void GrGLSpotLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001555 const SkLight* light) const {
1556 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001557 SkASSERT(light->type() == SkLight::kSpot_LightType);
1558 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001559 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001560 uman.set1f(fExponentUni, spotLight->specularExponent());
1561 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1562 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1563 uman.set1f(fConeScaleUni, spotLight->coneScale());
1564 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001565}
1566
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001567void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001568 const char* location;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001569 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001570 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001571 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1572 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001573}
1574
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001575void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1576 const char *surfaceToLight) {
1577
1578 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1579
1580 const char* exponent;
1581 const char* cosInner;
1582 const char* cosOuter;
1583 const char* coneScale;
1584 const char* s;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001585 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001586 kFloat_GrSLType, "Exponent", &exponent);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001587 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001588 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001589 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001590 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001591 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001592 kFloat_GrSLType, "ConeScale", &coneScale);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001593 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001594 kVec3f_GrSLType, "S", &s);
1595
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001596 static const GrGLShaderVar gLightColorArgs[] = {
1597 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1598 };
1599 SkString lightColorBody;
1600 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1601 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1602 lightColorBody.appendf("\t\treturn vec3(0);\n");
1603 lightColorBody.appendf("\t}\n");
1604 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1605 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1606 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1607 color, cosOuter, coneScale);
1608 lightColorBody.appendf("\t}\n");
1609 lightColorBody.appendf("\treturn %s;\n", color);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001610 builder->fsEmitFunction(kVec3f_GrSLType,
1611 "lightColor",
1612 SK_ARRAY_COUNT(gLightColorArgs),
1613 gLightColorArgs,
1614 lightColorBody.c_str(),
1615 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001616
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001617 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001618}
1619
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001620#endif
1621
djsollen@google.com08337772012-06-26 14:33:13 +00001622SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1623 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1624 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001625SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END