blob: 95e9965f29e91df578693a08529f5f5f3a59ced9 [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"
joshualitt30ba4362014-08-21 20:18:45 -070020#include "gl/builders/GrGLProgramBuilder.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
kkinnunen7510b222014-07-30 00:04:16 -070028typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000029#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000030
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000031namespace {
32
33const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
34const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000035const SkScalar gOneHalf = 0.5f;
36const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000038#if SK_SUPPORT_GPU
kkinnunen7510b222014-07-30 00:04:16 -070039void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000040 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070041 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000042}
43
kkinnunen7510b222014-07-30 00:04:16 -070044void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni, const SkPoint3& point) {
45 setUniformPoint3(pdman, 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:
reed9fa60da2014-08-21 07:59:51 -0700267 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco5e5f9482014-08-26 12:27:12 -0700268 const CropRect*, uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700269
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000271 SkScalar kd() const { return fKD; }
272
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000273protected:
reed9fa60da2014-08-21 07:59:51 -0700274 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700275 SkScalar kd, SkImageFilter* input, const CropRect* cropRect,
276 uint32_t uniqueID);
reed9fa60da2014-08-21 07:59:51 -0700277#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000278 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -0700279#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000280 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000281 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000282 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000283#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700284 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
285 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000286#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000287
288private:
reed9fa60da2014-08-21 07:59:51 -0700289 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290 typedef SkLightingImageFilter INHERITED;
291 SkScalar fKD;
292};
293
294class SkSpecularLightingImageFilter : public SkLightingImageFilter {
295public:
reed9fa60da2014-08-21 07:59:51 -0700296 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700297 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*, uint32_t uniqueID = 0);
reed9fa60da2014-08-21 07:59:51 -0700298
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000299 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
300
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000301 SkScalar ks() const { return fKS; }
302 SkScalar shininess() const { return fShininess; }
303
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000304protected:
reed9fa60da2014-08-21 07:59:51 -0700305 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco5e5f9482014-08-26 12:27:12 -0700306 SkScalar shininess, SkImageFilter* input, const CropRect*,
307 uint32_t uniqueID);
reed9fa60da2014-08-21 07:59:51 -0700308#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000309 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -0700310#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000311 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000312 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000313 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000314#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700315 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
316 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000317#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000318
319private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000320 SkScalar fKS;
321 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700322 friend class SkLightingImageFilter;
323 typedef SkLightingImageFilter INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000324};
325
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000326#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000327
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000328class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000329public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000330 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000331 virtual ~GrLightingEffect();
332
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000333 const SkLight* light() const { return fLight; }
334 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000335 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000336
337 virtual void getConstantColorComponents(GrColor* color,
338 uint32_t* validFlags) const SK_OVERRIDE {
339 // lighting shaders are complicated. We just throw up our hands.
340 *validFlags = 0;
341 }
342
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000343protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000344 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000345
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000346private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000347 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000348 const SkLight* fLight;
349 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000350 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000351};
352
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000353class GrDiffuseLightingEffect : public GrLightingEffect {
354public:
bsalomon83d081a2014-07-08 09:56:10 -0700355 static GrEffect* Create(GrTexture* texture,
356 const SkLight* light,
357 SkScalar surfaceScale,
358 const SkMatrix& matrix,
359 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700360 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
361 light,
362 surfaceScale,
363 matrix,
364 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000365 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000366
367 static const char* Name() { return "DiffuseLighting"; }
368
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000369 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000370
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000371 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000372 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000373
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000374private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000375 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000376
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000377 GrDiffuseLightingEffect(GrTexture* texture,
378 const SkLight* light,
379 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000380 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000381 SkScalar kd);
382
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000383 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000384 typedef GrLightingEffect INHERITED;
385 SkScalar fKD;
386};
387
388class GrSpecularLightingEffect : public GrLightingEffect {
389public:
bsalomon83d081a2014-07-08 09:56:10 -0700390 static GrEffect* Create(GrTexture* texture,
391 const SkLight* light,
392 SkScalar surfaceScale,
393 const SkMatrix& matrix,
394 SkScalar ks,
395 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700396 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
397 light,
398 surfaceScale,
399 matrix,
400 ks,
401 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000402 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000403 static const char* Name() { return "SpecularLighting"; }
404
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000405 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000406
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000407 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000408 SkScalar ks() const { return fKS; }
409 SkScalar shininess() const { return fShininess; }
410
411private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000412 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000413
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000414 GrSpecularLightingEffect(GrTexture* texture,
415 const SkLight* light,
416 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000417 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000418 SkScalar ks,
419 SkScalar shininess);
420
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000421 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000422 typedef GrLightingEffect INHERITED;
423 SkScalar fKS;
424 SkScalar fShininess;
425};
426
427///////////////////////////////////////////////////////////////////////////////
428
429class GrGLLight {
430public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000431 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000432
433 /**
434 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
435 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
436 */
joshualitt30ba4362014-08-21 20:18:45 -0700437 void emitLightColorUniform(GrGLProgramBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000438
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000439 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000440 * These two functions are called from GrGLLightingEffect's emitCode() function.
441 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
442 * the light. The expression will be used in the FS. emitLightColor writes an expression into
443 * the FS that is the color of the light. Either function may add functions and/or uniforms to
444 * the FS. The default of emitLightColor appends the name of the constant light color uniform
445 * and so this function only needs to be overridden if the light color varies spatially.
446 */
joshualitt30ba4362014-08-21 20:18:45 -0700447 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) = 0;
448 virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000449
450 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
451 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700452 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000453 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000454
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000455protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000456 /**
457 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
458 * function.
459 */
460 UniformHandle lightColorUni() const { return fColorUni; }
461
462private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000463 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000464
465 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000466};
467
468///////////////////////////////////////////////////////////////////////////////
469
470class GrGLDistantLight : public GrGLLight {
471public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000472 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700473 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000474 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700475 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000476
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000477private:
478 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000479 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000480};
481
482///////////////////////////////////////////////////////////////////////////////
483
484class GrGLPointLight : public GrGLLight {
485public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000486 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700487 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000488 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700489 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000490
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491private:
492 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000493 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494};
495
496///////////////////////////////////////////////////////////////////////////////
497
498class GrGLSpotLight : public GrGLLight {
499public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000500 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700501 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000502 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700503 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
504 virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000505
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506private:
507 typedef GrGLLight INHERITED;
508
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000509 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000510 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000511 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000512 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000513 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000514 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000515 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000516};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000517#else
518
519class GrGLLight;
520
521#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000522
523};
524
525///////////////////////////////////////////////////////////////////////////////
526
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000527class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000528public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000529 SK_DECLARE_INST_COUNT(SkLight)
530
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000531 enum LightType {
532 kDistant_LightType,
533 kPoint_LightType,
534 kSpot_LightType,
535 };
536 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000537 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000538 virtual GrGLLight* createGLLight() const = 0;
539 virtual bool isEqual(const SkLight& other) const {
540 return fColor == other.fColor;
541 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000542 // Called to know whether the generated GrGLLight will require access to the fragment position.
543 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000544 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000545
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000546 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000547 void flattenLight(SkWriteBuffer& buffer) const;
548 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000549
djsollen@google.com08337772012-06-26 14:33:13 +0000550protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000551 SkLight(SkColor color)
552 : fColor(SkIntToScalar(SkColorGetR(color)),
553 SkIntToScalar(SkColorGetG(color)),
554 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000555 SkLight(const SkPoint3& color)
556 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000557 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000558 fColor = readPoint3(buffer);
559 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000560
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000561 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000562
djsollen@google.com08337772012-06-26 14:33:13 +0000563
564private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000565 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000566 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000567};
568
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000569///////////////////////////////////////////////////////////////////////////////
570
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000571class SkDistantLight : public SkLight {
572public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000573 SkDistantLight(const SkPoint3& direction, SkColor color)
574 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000575 }
djsollen@google.com08337772012-06-26 14:33:13 +0000576
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000577 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
578 return fDirection;
579 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000580 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000581 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000582 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000583 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
584#if SK_SUPPORT_GPU
585 return SkNEW(GrGLDistantLight);
586#else
587 SkDEBUGFAIL("Should not call in GPU-less build");
588 return NULL;
589#endif
590 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000591 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
592
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000593 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
594 if (other.type() != kDistant_LightType) {
595 return false;
596 }
597
598 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
599 return INHERITED::isEqual(other) &&
600 fDirection == o.fDirection;
601 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000602
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000603 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000604 fDirection = readPoint3(buffer);
605 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000606
djsollen@google.com08337772012-06-26 14:33:13 +0000607protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000608 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
609 : INHERITED(color), fDirection(direction) {
610 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000611 virtual SkLight* transform(const SkMatrix& matrix) const {
612 return new SkDistantLight(direction(), color());
613 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000614 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000615 writePoint3(fDirection, buffer);
616 }
617
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618private:
djsollen@google.com08337772012-06-26 14:33:13 +0000619 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000620 SkPoint3 fDirection;
621};
622
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000623///////////////////////////////////////////////////////////////////////////////
624
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000625class SkPointLight : public SkLight {
626public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000627 SkPointLight(const SkPoint3& location, SkColor color)
628 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000629
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000630 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
631 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
632 fLocation.fY - SkIntToScalar(y),
633 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
634 direction.normalize();
635 return direction;
636 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000637 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000638 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000639 const SkPoint3& location() const { return fLocation; }
640 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000641#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000642 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000643#else
644 SkDEBUGFAIL("Should not call in GPU-less build");
645 return NULL;
646#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000647 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000648 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000649 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000650 if (other.type() != kPoint_LightType) {
651 return false;
652 }
653 const SkPointLight& o = static_cast<const SkPointLight&>(other);
654 return INHERITED::isEqual(other) &&
655 fLocation == o.fLocation;
656 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000657 virtual SkLight* transform(const SkMatrix& matrix) const {
658 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
659 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000660 // Use X scale and Y scale on Z and average the result
661 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
662 matrix.mapVectors(&locationZ, 1);
663 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000664 return new SkPointLight(location, color());
665 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000666
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000667 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000668 fLocation = readPoint3(buffer);
669 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000670
671protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000672 SkPointLight(const SkPoint3& location, const SkPoint3& color)
673 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000674 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000675 writePoint3(fLocation, buffer);
676 }
677
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000678private:
djsollen@google.com08337772012-06-26 14:33:13 +0000679 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000680 SkPoint3 fLocation;
681};
682
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000683///////////////////////////////////////////////////////////////////////////////
684
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000685class SkSpotLight : public SkLight {
686public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000687 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
688 : INHERITED(color),
689 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000690 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000691 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000692 {
693 fS = target - location;
694 fS.normalize();
695 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000696 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000697 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
698 fConeScale = SkScalarInvert(antiAliasThreshold);
699 }
djsollen@google.com08337772012-06-26 14:33:13 +0000700
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000701 virtual SkLight* transform(const SkMatrix& matrix) const {
702 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
703 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000704 // Use X scale and Y scale on Z and average the result
705 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
706 matrix.mapVectors(&locationZ, 1);
707 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000708 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
709 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000710 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
711 matrix.mapVectors(&targetZ, 1);
712 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
713 SkPoint3 s = target - location;
714 s.normalize();
715 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000716 }
717
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000718 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
719 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
720 fLocation.fY - SkIntToScalar(y),
721 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
722 direction.normalize();
723 return direction;
724 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000725 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000726 SkScalar cosAngle = -surfaceToLight.dot(fS);
727 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000728 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000729 }
730 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
731 if (cosAngle < fCosInnerConeAngle) {
732 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000733 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000734 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000735 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000736 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000737 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000738#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000739 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000740#else
741 SkDEBUGFAIL("Should not call in GPU-less build");
742 return NULL;
743#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000744 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000745 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000746 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000747 const SkPoint3& location() const { return fLocation; }
748 const SkPoint3& target() const { return fTarget; }
749 SkScalar specularExponent() const { return fSpecularExponent; }
750 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
751 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
752 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000753 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000754
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000755 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000756 fLocation = readPoint3(buffer);
757 fTarget = readPoint3(buffer);
758 fSpecularExponent = buffer.readScalar();
759 fCosOuterConeAngle = buffer.readScalar();
760 fCosInnerConeAngle = buffer.readScalar();
761 fConeScale = buffer.readScalar();
762 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000763 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
764 SkScalarIsFinite(fCosOuterConeAngle) &&
765 SkScalarIsFinite(fCosInnerConeAngle) &&
766 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000767 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000768protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000769 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
770 : INHERITED(color),
771 fLocation(location),
772 fTarget(target),
773 fSpecularExponent(specularExponent),
774 fCosOuterConeAngle(cosOuterConeAngle),
775 fCosInnerConeAngle(cosInnerConeAngle),
776 fConeScale(coneScale),
777 fS(s)
778 {
779 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000780 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000781 writePoint3(fLocation, buffer);
782 writePoint3(fTarget, buffer);
783 buffer.writeScalar(fSpecularExponent);
784 buffer.writeScalar(fCosOuterConeAngle);
785 buffer.writeScalar(fCosInnerConeAngle);
786 buffer.writeScalar(fConeScale);
787 writePoint3(fS, buffer);
788 }
789
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000790 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000791 if (other.type() != kSpot_LightType) {
792 return false;
793 }
794
795 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
796 return INHERITED::isEqual(other) &&
797 fLocation == o.fLocation &&
798 fTarget == o.fTarget &&
799 fSpecularExponent == o.fSpecularExponent &&
800 fCosOuterConeAngle == o.fCosOuterConeAngle;
801 }
802
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000803private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000804 static const SkScalar kSpecularExponentMin;
805 static const SkScalar kSpecularExponentMax;
806
djsollen@google.com08337772012-06-26 14:33:13 +0000807 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000808 SkPoint3 fLocation;
809 SkPoint3 fTarget;
810 SkScalar fSpecularExponent;
811 SkScalar fCosOuterConeAngle;
812 SkScalar fCosInnerConeAngle;
813 SkScalar fConeScale;
814 SkPoint3 fS;
815};
816
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000817// According to the spec, the specular term should be in the range [1, 128] :
818// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000819const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
820const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000821
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000822///////////////////////////////////////////////////////////////////////////////
823
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000824void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000825 // Write type first, then baseclass, then subclass.
826 buffer.writeInt(this->type());
827 writePoint3(fColor, buffer);
828 this->onFlattenLight(buffer);
829}
830
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000831/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000832 // Read type first.
833 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
834 switch (type) {
835 // Each of these constructors must first call SkLight's, so we'll read the baseclass
836 // then subclass, same order as flattenLight.
837 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
838 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
839 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
840 default:
841 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000842 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000843 return NULL;
844 }
845}
846///////////////////////////////////////////////////////////////////////////////
847
senorblanco9ea3d572014-07-08 09:16:22 -0700848SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700849 SkImageFilter* input, const CropRect* cropRect,
850 uint32_t uniqueID)
851 : INHERITED(1, &input, cropRect, uniqueID)
reed9fa60da2014-08-21 07:59:51 -0700852 , fLight(SkRef(light))
853 , fSurfaceScale(surfaceScale / 255)
854{}
855
856SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
857 SkColor lightColor,
858 SkScalar surfaceScale,
859 SkScalar kd,
860 SkImageFilter* input,
861 const CropRect* cropRect) {
862 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
863 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000864}
865
reed9fa60da2014-08-21 07:59:51 -0700866SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
867 SkColor lightColor,
868 SkScalar surfaceScale,
869 SkScalar kd,
870 SkImageFilter* input,
871 const CropRect* cropRect) {
872 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
873 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000874}
875
reed9fa60da2014-08-21 07:59:51 -0700876SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
877 const SkPoint3& target,
878 SkScalar specularExponent,
879 SkScalar cutoffAngle,
880 SkColor lightColor,
881 SkScalar surfaceScale,
882 SkScalar kd,
883 SkImageFilter* input,
884 const CropRect* cropRect) {
885 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
886 cutoffAngle, lightColor)));
887 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000888}
889
reed9fa60da2014-08-21 07:59:51 -0700890SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
891 SkColor lightColor,
892 SkScalar surfaceScale,
893 SkScalar ks,
894 SkScalar shine,
895 SkImageFilter* input,
896 const CropRect* cropRect) {
897 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
898 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000899}
900
reed9fa60da2014-08-21 07:59:51 -0700901SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
902 SkColor lightColor,
903 SkScalar surfaceScale,
904 SkScalar ks,
905 SkScalar shine,
906 SkImageFilter* input,
907 const CropRect* cropRect) {
908 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
909 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910}
911
reed9fa60da2014-08-21 07:59:51 -0700912SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
913 const SkPoint3& target,
914 SkScalar specularExponent,
915 SkScalar cutoffAngle,
916 SkColor lightColor,
917 SkScalar surfaceScale,
918 SkScalar ks,
919 SkScalar shine,
920 SkImageFilter* input,
921 const CropRect* cropRect) {
922 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
923 cutoffAngle, lightColor)));
924 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000925}
926
reed9fa60da2014-08-21 07:59:51 -0700927SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000928
reed9fa60da2014-08-21 07:59:51 -0700929#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000930SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000931 : INHERITED(1, buffer) {
reed9fa60da2014-08-21 07:59:51 -0700932 fLight.reset(SkLight::UnflattenLight(buffer));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000933 fSurfaceScale = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000934 buffer.validate(SkScalarIsFinite(fSurfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000935}
reed9fa60da2014-08-21 07:59:51 -0700936#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000937
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000938void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000939 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000940 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700941 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000942}
943
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000944///////////////////////////////////////////////////////////////////////////////
945
reed9fa60da2014-08-21 07:59:51 -0700946SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -0700947 SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -0700948 if (NULL == light) {
949 return NULL;
950 }
951 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
952 return NULL;
953 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000954 // According to the spec, kd can be any non-negative number :
955 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700956 if (kd < 0) {
957 return NULL;
958 }
senorblanco5e5f9482014-08-26 12:27:12 -0700959 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -0700960}
961
senorblanco5e5f9482014-08-26 12:27:12 -0700962SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
963 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -0700964 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000965{
966}
967
reed9fa60da2014-08-21 07:59:51 -0700968#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000969SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000970 : INHERITED(buffer)
971{
972 fKD = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000973 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000974}
reed9fa60da2014-08-21 07:59:51 -0700975#endif
976
977SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
978 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
979 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
980 SkScalar surfaceScale = buffer.readScalar();
981 SkScalar kd = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -0700982 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -0700983}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000984
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000985void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000986 this->INHERITED::flatten(buffer);
987 buffer.writeScalar(fKD);
988}
989
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000990bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
991 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000992 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000993 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000994 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000995 SkImageFilter* input = getInput(0);
996 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000997 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000998 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000999 return false;
1000 }
1001
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001002 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001003 return false;
1004 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001005 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001006 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001007 return false;
1008 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001009
1010 if (bounds.width() < 2 || bounds.height() < 2) {
1011 return false;
1012 }
1013
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001014 SkAutoLockPixels alp(src);
1015 if (!src.getPixels()) {
1016 return false;
1017 }
1018
reed84825042014-09-02 12:50:45 -07001019 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001020 return false;
1021 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001022
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001023 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001024
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001025 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001026 offset->fX = bounds.left();
1027 offset->fY = bounds.top();
1028 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001029 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001030 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001031 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001032 break;
1033 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001034 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001035 break;
1036 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001037 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001038 break;
1039 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001040
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001041 return true;
1042}
1043
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001044#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -07001045bool SkDiffuseLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
1046 const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001047 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001048 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001049 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001050 }
1051 return true;
1052}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001053#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001054
1055///////////////////////////////////////////////////////////////////////////////
1056
reed9fa60da2014-08-21 07:59:51 -07001057SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco5e5f9482014-08-26 12:27:12 -07001058 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
reed9fa60da2014-08-21 07:59:51 -07001059 if (NULL == light) {
1060 return NULL;
1061 }
1062 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1063 return NULL;
1064 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001065 // According to the spec, ks can be any non-negative number :
1066 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001067 if (ks < 0) {
1068 return NULL;
1069 }
1070 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco5e5f9482014-08-26 12:27:12 -07001071 (light, surfaceScale, ks, shininess, input, cropRect, uniqueID));
reed9fa60da2014-08-21 07:59:51 -07001072}
1073
senorblanco5e5f9482014-08-26 12:27:12 -07001074SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
1075 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
reed9fa60da2014-08-21 07:59:51 -07001076 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001077 fShininess(shininess)
1078{
1079}
1080
reed9fa60da2014-08-21 07:59:51 -07001081#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001082SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
reed9fa60da2014-08-21 07:59:51 -07001083 : INHERITED(buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001084{
1085 fKS = buffer.readScalar();
1086 fShininess = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001087 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001088 SkScalarIsFinite(fShininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001089}
reed9fa60da2014-08-21 07:59:51 -07001090#endif
1091
1092SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1093 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1094 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1095 SkScalar surfaceScale = buffer.readScalar();
1096 SkScalar ks = buffer.readScalar();
1097 SkScalar shine = buffer.readScalar();
senorblanco5e5f9482014-08-26 12:27:12 -07001098 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect(), common.uniqueID());
reed9fa60da2014-08-21 07:59:51 -07001099}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001100
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001101void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001102 this->INHERITED::flatten(buffer);
1103 buffer.writeScalar(fKS);
1104 buffer.writeScalar(fShininess);
1105}
1106
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001107bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1108 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001109 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001110 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001111 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001112 SkImageFilter* input = getInput(0);
1113 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001114 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001115 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001116 return false;
1117 }
1118
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001119 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001120 return false;
1121 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001122
1123 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001124 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001125 return false;
1126 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001127
1128 if (bounds.width() < 2 || bounds.height() < 2) {
1129 return false;
1130 }
1131
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001132 SkAutoLockPixels alp(src);
1133 if (!src.getPixels()) {
1134 return false;
1135 }
1136
reed84825042014-09-02 12:50:45 -07001137 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001138 return false;
1139 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001140
1141 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001142 offset->fX = bounds.left();
1143 offset->fY = bounds.top();
1144 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001145 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001146 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001147 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001148 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001149 break;
1150 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001151 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001152 break;
1153 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001154 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001155 break;
1156 }
1157 return true;
1158}
1159
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001160#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -07001161bool SkSpecularLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
1162 const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001163 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001164 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001165 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001166 }
1167 return true;
1168}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001169#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001170
1171///////////////////////////////////////////////////////////////////////////////
1172
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001173#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001174
1175namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001176SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001177 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1178 SkScalarToFloat(random->nextSScalar1()),
1179 SkScalarToFloat(random->nextSScalar1()));
1180}
1181
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001182SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001183 int type = random->nextULessThan(3);
1184 switch (type) {
1185 case 0: {
1186 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1187 }
1188 case 1: {
1189 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1190 }
1191 case 2: {
1192 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1193 random_point3(random),
1194 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001195 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001196 random->nextU()));
1197 }
1198 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001199 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001200 return NULL;
1201 }
1202}
1203
1204}
1205
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001206class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001207public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001208 GrGLLightingEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001209 const GrEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001210 virtual ~GrGLLightingEffect();
1211
joshualitt30ba4362014-08-21 20:18:45 -07001212 virtual void emitCode(GrGLProgramBuilder*,
joshualitt49586be2014-09-16 08:21:41 -07001213 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -07001214 const GrEffectKey&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001215 const char* outputColor,
1216 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001217 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001218 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001219
joshualitt49586be2014-09-16 08:21:41 -07001220 static inline void GenKey(const GrEffect&, const GrGLCaps&, GrEffectKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001221
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001222 /**
1223 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1224 */
joshualitt49586be2014-09-16 08:21:41 -07001225 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001226
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001227protected:
joshualitt30ba4362014-08-21 20:18:45 -07001228 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001229
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001230private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001231 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001232
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001233 UniformHandle fImageIncrementUni;
1234 UniformHandle fSurfaceScaleUni;
1235 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001236};
1237
1238///////////////////////////////////////////////////////////////////////////////
1239
1240class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1241public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001242 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001243 const GrEffect& effect);
joshualitt30ba4362014-08-21 20:18:45 -07001244 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -07001245 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001246
1247private:
1248 typedef GrGLLightingEffect INHERITED;
1249
bsalomon@google.com032b2212012-07-16 13:36:18 +00001250 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001251};
1252
1253///////////////////////////////////////////////////////////////////////////////
1254
1255class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1256public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001257 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001258 const GrEffect& effect);
joshualitt30ba4362014-08-21 20:18:45 -07001259 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -07001260 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001261
1262private:
1263 typedef GrGLLightingEffect INHERITED;
1264
bsalomon@google.com032b2212012-07-16 13:36:18 +00001265 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001266 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001267};
1268
1269///////////////////////////////////////////////////////////////////////////////
1270
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001271GrLightingEffect::GrLightingEffect(GrTexture* texture,
1272 const SkLight* light,
1273 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001274 const SkMatrix& matrix)
bsalomon6267f812014-08-29 15:05:53 -07001275 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001276 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001277 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001278 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001279 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001280 if (light->requiresFragmentPosition()) {
1281 this->setWillReadFragmentPosition();
1282 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001283}
1284
1285GrLightingEffect::~GrLightingEffect() {
1286 fLight->unref();
1287}
1288
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001289bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001290 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001291 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001292 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001293 fSurfaceScale == s.fSurfaceScale;
1294}
1295
1296///////////////////////////////////////////////////////////////////////////////
1297
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001298GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1299 const SkLight* light,
1300 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001301 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001302 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001303 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001304}
1305
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001306const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1307 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001308}
1309
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001310bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001311 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001312 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001313 this->kd() == s.kd();
1314}
1315
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001316GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001317
bsalomon83d081a2014-07-08 09:56:10 -07001318GrEffect* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1319 GrContext* context,
1320 const GrDrawTargetCaps&,
1321 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001322 SkScalar surfaceScale = random->nextSScalar1();
1323 SkScalar kd = random->nextUScalar1();
1324 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001325 SkMatrix matrix;
1326 for (int i = 0; i < 9; i++) {
1327 matrix[i] = random->nextUScalar1();
1328 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001329 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001330 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001331}
1332
1333
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001334///////////////////////////////////////////////////////////////////////////////
1335
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001336GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001337 const GrEffect& effect)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001338 : INHERITED(factory) {
joshualitt49586be2014-09-16 08:21:41 -07001339 const GrLightingEffect& m = effect.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001340 fLight = m.light()->createGLLight();
1341}
1342
1343GrGLLightingEffect::~GrGLLightingEffect() {
1344 delete fLight;
1345}
1346
joshualitt30ba4362014-08-21 20:18:45 -07001347void GrGLLightingEffect::emitCode(GrGLProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -07001348 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -07001349 const GrEffectKey& key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001350 const char* outputColor,
1351 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001352 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001353 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001354 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001355 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001356 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001357 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001358 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001359 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001360 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001361 SkString lightFunc;
1362 this->emitLightFunc(builder, &lightFunc);
1363 static const GrGLShaderVar gSobelArgs[] = {
1364 GrGLShaderVar("a", kFloat_GrSLType),
1365 GrGLShaderVar("b", kFloat_GrSLType),
1366 GrGLShaderVar("c", kFloat_GrSLType),
1367 GrGLShaderVar("d", kFloat_GrSLType),
1368 GrGLShaderVar("e", kFloat_GrSLType),
1369 GrGLShaderVar("f", kFloat_GrSLType),
1370 GrGLShaderVar("scale", kFloat_GrSLType),
1371 };
1372 SkString sobelFuncName;
joshualitt30ba4362014-08-21 20:18:45 -07001373 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1374 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1375
1376 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001377 "sobel",
1378 SK_ARRAY_COUNT(gSobelArgs),
1379 gSobelArgs,
1380 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1381 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001382 static const GrGLShaderVar gPointToNormalArgs[] = {
1383 GrGLShaderVar("x", kFloat_GrSLType),
1384 GrGLShaderVar("y", kFloat_GrSLType),
1385 GrGLShaderVar("scale", kFloat_GrSLType),
1386 };
1387 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001388 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001389 "pointToNormal",
1390 SK_ARRAY_COUNT(gPointToNormalArgs),
1391 gPointToNormalArgs,
1392 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1393 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001394
1395 static const GrGLShaderVar gInteriorNormalArgs[] = {
1396 GrGLShaderVar("m", kFloat_GrSLType, 9),
1397 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1398 };
1399 SkString interiorNormalBody;
1400 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1401 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1402 "\t surfaceScale);\n",
1403 pointToNormalName.c_str(),
1404 sobelFuncName.c_str(),
1405 sobelFuncName.c_str());
1406 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001407 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001408 "interiorNormal",
1409 SK_ARRAY_COUNT(gInteriorNormalArgs),
1410 gInteriorNormalArgs,
1411 interiorNormalBody.c_str(),
1412 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001413
joshualitt30ba4362014-08-21 20:18:45 -07001414 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1415 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001416
1417 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1418 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1419
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001420 int index = 0;
1421 for (int dy = -1; dy <= 1; dy++) {
1422 for (int dx = -1; dx <= 1; dx++) {
1423 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001424 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001425 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1426 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1427 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001428 }
1429 }
joshualitt30ba4362014-08-21 20:18:45 -07001430 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001431 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001432 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001433 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001434 fsBuilder->codeAppend(";\n");
1435 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001436 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001437 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001438 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001439 SkString modulate;
1440 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001441 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001442}
1443
joshualitt49586be2014-09-16 08:21:41 -07001444void GrGLLightingEffect::GenKey(const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -07001445 const GrGLCaps& caps, GrEffectKeyBuilder* b) {
joshualitt49586be2014-09-16 08:21:41 -07001446 b->add32(effect.cast<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001447}
1448
kkinnunen7510b222014-07-30 00:04:16 -07001449void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -07001450 const GrEffect& effect) {
1451 const GrLightingEffect& lighting = effect.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001452 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001453 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001454 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1455 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001456 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001457 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001458}
1459
1460///////////////////////////////////////////////////////////////////////////////
1461
1462///////////////////////////////////////////////////////////////////////////////
1463
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001464GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001465 const GrEffect& effect)
1466 : INHERITED(factory, effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001467}
1468
joshualitt30ba4362014-08-21 20:18:45 -07001469void GrGLDiffuseLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001470 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001471 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001472 kFloat_GrSLType,
1473 "KD",
1474 &kd);
1475
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001476 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("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1483 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001484 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1485 "light",
1486 SK_ARRAY_COUNT(gLightArgs),
1487 gLightArgs,
1488 lightBody.c_str(),
1489 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001490}
1491
kkinnunen7510b222014-07-30 00:04:16 -07001492void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -07001493 const GrEffect& effect) {
1494 INHERITED::setData(pdman, effect);
1495 const GrDiffuseLightingEffect& diffuse = effect.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001496 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001497}
1498
1499///////////////////////////////////////////////////////////////////////////////
1500
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001501GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1502 const SkLight* light,
1503 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001504 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001505 SkScalar ks,
1506 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001507 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001508 fKS(ks),
1509 fShininess(shininess) {
1510}
1511
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001512const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1513 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001514}
1515
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001516bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001517 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001518 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001519 this->ks() == s.ks() &&
1520 this->shininess() == s.shininess();
1521}
1522
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001523GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001524
bsalomon83d081a2014-07-08 09:56:10 -07001525GrEffect* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1526 GrContext* context,
1527 const GrDrawTargetCaps&,
1528 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001529 SkScalar surfaceScale = random->nextSScalar1();
1530 SkScalar ks = random->nextUScalar1();
1531 SkScalar shininess = random->nextUScalar1();
1532 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001533 SkMatrix matrix;
1534 for (int i = 0; i < 9; i++) {
1535 matrix[i] = random->nextUScalar1();
1536 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001537 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001538 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001539}
1540
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001541///////////////////////////////////////////////////////////////////////////////
1542
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001543GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001544 const GrEffect& effect)
1545 : INHERITED(factory, effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001546}
1547
joshualitt30ba4362014-08-21 20:18:45 -07001548void GrGLSpecularLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001549 const char* ks;
1550 const char* shininess;
1551
joshualitt30ba4362014-08-21 20:18:45 -07001552 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001553 kFloat_GrSLType, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001554 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001555 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001556
1557 static const GrGLShaderVar gLightArgs[] = {
1558 GrGLShaderVar("normal", kVec3f_GrSLType),
1559 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1560 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1561 };
1562 SkString lightBody;
1563 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1564 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001565 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1566 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001567 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1568 "light",
1569 SK_ARRAY_COUNT(gLightArgs),
1570 gLightArgs,
1571 lightBody.c_str(),
1572 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001573}
1574
kkinnunen7510b222014-07-30 00:04:16 -07001575void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -07001576 const GrEffect& effect) {
1577 INHERITED::setData(pdman, effect);
1578 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001579 pdman.set1f(fKSUni, spec.ks());
1580 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001581}
1582
1583///////////////////////////////////////////////////////////////////////////////
joshualitt30ba4362014-08-21 20:18:45 -07001584void GrGLLight::emitLightColorUniform(GrGLProgramBuilder* builder) {
1585 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001586 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001587}
1588
joshualitt30ba4362014-08-21 20:18:45 -07001589void GrGLLight::emitLightColor(GrGLProgramBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001590 const char *surfaceToLight) {
joshualitt30ba4362014-08-21 20:18:45 -07001591 builder->getFragmentShaderBuilder()->
1592 codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001593}
1594
kkinnunen7510b222014-07-30 00:04:16 -07001595void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001596 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001597 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001598}
1599
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001600///////////////////////////////////////////////////////////////////////////////
1601
kkinnunen7510b222014-07-30 00:04:16 -07001602void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001603 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001604 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001605 SkASSERT(light->type() == SkLight::kDistant_LightType);
1606 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001607 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001608}
1609
joshualitt30ba4362014-08-21 20:18:45 -07001610void GrGLDistantLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001611 const char* dir;
joshualitt30ba4362014-08-21 20:18:45 -07001612 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001613 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001614 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001615}
1616
1617///////////////////////////////////////////////////////////////////////////////
1618
kkinnunen7510b222014-07-30 00:04:16 -07001619void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001620 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001621 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001622 SkASSERT(light->type() == SkLight::kPoint_LightType);
1623 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001624 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001625}
1626
joshualitt30ba4362014-08-21 20:18:45 -07001627void GrGLPointLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001628 const char* loc;
joshualitt30ba4362014-08-21 20:18:45 -07001629 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001630 "LightLocation", &loc);
joshualitt30ba4362014-08-21 20:18:45 -07001631 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1632 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1633 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001634}
1635
1636///////////////////////////////////////////////////////////////////////////////
1637
kkinnunen7510b222014-07-30 00:04:16 -07001638void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001639 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001640 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001641 SkASSERT(light->type() == SkLight::kSpot_LightType);
1642 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001643 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1644 pdman.set1f(fExponentUni, spotLight->specularExponent());
1645 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1646 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1647 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1648 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001649}
1650
joshualitt30ba4362014-08-21 20:18:45 -07001651void GrGLSpotLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001652 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001653 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001654 kVec3f_GrSLType, "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001655
1656 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1657 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1658 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001659}
1660
joshualitt30ba4362014-08-21 20:18:45 -07001661void GrGLSpotLight::emitLightColor(GrGLProgramBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001662 const char *surfaceToLight) {
1663
1664 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1665
1666 const char* exponent;
1667 const char* cosInner;
1668 const char* cosOuter;
1669 const char* coneScale;
1670 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001671 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001672 kFloat_GrSLType, "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001673 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001674 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001675 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001676 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001677 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001678 kFloat_GrSLType, "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001679 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001680 kVec3f_GrSLType, "S", &s);
1681
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001682 static const GrGLShaderVar gLightColorArgs[] = {
1683 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1684 };
1685 SkString lightColorBody;
1686 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1687 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1688 lightColorBody.appendf("\t\treturn vec3(0);\n");
1689 lightColorBody.appendf("\t}\n");
1690 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1691 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1692 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1693 color, cosOuter, coneScale);
1694 lightColorBody.appendf("\t}\n");
1695 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt30ba4362014-08-21 20:18:45 -07001696 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1697 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001698 "lightColor",
1699 SK_ARRAY_COUNT(gLightColorArgs),
1700 gLightColorArgs,
1701 lightColorBody.c_str(),
1702 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001703
joshualitt30ba4362014-08-21 20:18:45 -07001704 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001705}
1706
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001707#endif
1708
djsollen@google.com08337772012-06-26 14:33:13 +00001709SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1710 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1711 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001712SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END