blob: c3834c697710c203851e60847f51bdbc2c664246 [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*,
268 const CropRect*);
269
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,
275 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
276#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000277 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -0700278#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000279 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000280 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000281 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000282#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700283 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
284 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000285#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286
287private:
reed9fa60da2014-08-21 07:59:51 -0700288 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289 typedef SkLightingImageFilter INHERITED;
290 SkScalar fKD;
291};
292
293class SkSpecularLightingImageFilter : public SkLightingImageFilter {
294public:
reed9fa60da2014-08-21 07:59:51 -0700295 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
296 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
297
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000298 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
299
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000300 SkScalar ks() const { return fKS; }
301 SkScalar shininess() const { return fShininess; }
302
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000303protected:
reed9fa60da2014-08-21 07:59:51 -0700304 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
305 SkScalar shininess, SkImageFilter* input, const CropRect*);
306#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000307 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -0700308#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000309 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000310 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000311 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000312#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -0700313 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
314 const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000315#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000316
317private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000318 SkScalar fKS;
319 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700320 friend class SkLightingImageFilter;
321 typedef SkLightingImageFilter INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000322};
323
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000324#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000325
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000326class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000327public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000328 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000329 virtual ~GrLightingEffect();
330
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000331 const SkLight* light() const { return fLight; }
332 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000333 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000334
335 virtual void getConstantColorComponents(GrColor* color,
336 uint32_t* validFlags) const SK_OVERRIDE {
337 // lighting shaders are complicated. We just throw up our hands.
338 *validFlags = 0;
339 }
340
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000341protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000342 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000343
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000344private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000345 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000346 const SkLight* fLight;
347 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000348 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000349};
350
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000351class GrDiffuseLightingEffect : public GrLightingEffect {
352public:
bsalomon83d081a2014-07-08 09:56:10 -0700353 static GrEffect* Create(GrTexture* texture,
354 const SkLight* light,
355 SkScalar surfaceScale,
356 const SkMatrix& matrix,
357 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700358 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
359 light,
360 surfaceScale,
361 matrix,
362 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000363 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000364
365 static const char* Name() { return "DiffuseLighting"; }
366
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000367 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000368
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000369 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000370 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000371
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000372private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000373 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000374
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000375 GrDiffuseLightingEffect(GrTexture* texture,
376 const SkLight* light,
377 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000378 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000379 SkScalar kd);
380
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000381 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000382 typedef GrLightingEffect INHERITED;
383 SkScalar fKD;
384};
385
386class GrSpecularLightingEffect : public GrLightingEffect {
387public:
bsalomon83d081a2014-07-08 09:56:10 -0700388 static GrEffect* Create(GrTexture* texture,
389 const SkLight* light,
390 SkScalar surfaceScale,
391 const SkMatrix& matrix,
392 SkScalar ks,
393 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700394 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
395 light,
396 surfaceScale,
397 matrix,
398 ks,
399 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000400 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000401 static const char* Name() { return "SpecularLighting"; }
402
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000403 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000404
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000405 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000406 SkScalar ks() const { return fKS; }
407 SkScalar shininess() const { return fShininess; }
408
409private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000410 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000411
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000412 GrSpecularLightingEffect(GrTexture* texture,
413 const SkLight* light,
414 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000415 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000416 SkScalar ks,
417 SkScalar shininess);
418
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000419 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000420 typedef GrLightingEffect INHERITED;
421 SkScalar fKS;
422 SkScalar fShininess;
423};
424
425///////////////////////////////////////////////////////////////////////////////
426
427class GrGLLight {
428public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000429 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000430
431 /**
432 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
433 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
434 */
joshualitt30ba4362014-08-21 20:18:45 -0700435 void emitLightColorUniform(GrGLProgramBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000436
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000437 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000438 * These two functions are called from GrGLLightingEffect's emitCode() function.
439 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
440 * the light. The expression will be used in the FS. emitLightColor writes an expression into
441 * the FS that is the color of the light. Either function may add functions and/or uniforms to
442 * the FS. The default of emitLightColor appends the name of the constant light color uniform
443 * and so this function only needs to be overridden if the light color varies spatially.
444 */
joshualitt30ba4362014-08-21 20:18:45 -0700445 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) = 0;
446 virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000447
448 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
449 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700450 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000451 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000452
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000453protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000454 /**
455 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
456 * function.
457 */
458 UniformHandle lightColorUni() const { return fColorUni; }
459
460private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000461 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000462
463 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000464};
465
466///////////////////////////////////////////////////////////////////////////////
467
468class GrGLDistantLight : public GrGLLight {
469public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000470 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700471 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000472 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700473 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000474
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000475private:
476 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000477 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000478};
479
480///////////////////////////////////////////////////////////////////////////////
481
482class GrGLPointLight : public GrGLLight {
483public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000484 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700485 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000486 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700487 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000488
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000489private:
490 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000491 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492};
493
494///////////////////////////////////////////////////////////////////////////////
495
496class GrGLSpotLight : public GrGLLight {
497public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000498 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700499 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000500 const SkLight* light) const SK_OVERRIDE;
joshualitt30ba4362014-08-21 20:18:45 -0700501 virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
502 virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000503
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000504private:
505 typedef GrGLLight INHERITED;
506
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000507 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000508 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000509 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000510 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000511 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000512 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000513 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000514};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000515#else
516
517class GrGLLight;
518
519#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000520
521};
522
523///////////////////////////////////////////////////////////////////////////////
524
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000525class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000526public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000527 SK_DECLARE_INST_COUNT(SkLight)
528
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000529 enum LightType {
530 kDistant_LightType,
531 kPoint_LightType,
532 kSpot_LightType,
533 };
534 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000535 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536 virtual GrGLLight* createGLLight() const = 0;
537 virtual bool isEqual(const SkLight& other) const {
538 return fColor == other.fColor;
539 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000540 // Called to know whether the generated GrGLLight will require access to the fragment position.
541 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000542 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000543
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000544 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000545 void flattenLight(SkWriteBuffer& buffer) const;
546 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000547
djsollen@google.com08337772012-06-26 14:33:13 +0000548protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000549 SkLight(SkColor color)
550 : fColor(SkIntToScalar(SkColorGetR(color)),
551 SkIntToScalar(SkColorGetG(color)),
552 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000553 SkLight(const SkPoint3& color)
554 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000555 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000556 fColor = readPoint3(buffer);
557 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000558
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000559 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000560
djsollen@google.com08337772012-06-26 14:33:13 +0000561
562private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000563 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000564 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000565};
566
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567///////////////////////////////////////////////////////////////////////////////
568
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000569class SkDistantLight : public SkLight {
570public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000571 SkDistantLight(const SkPoint3& direction, SkColor color)
572 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000573 }
djsollen@google.com08337772012-06-26 14:33:13 +0000574
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000575 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
576 return fDirection;
577 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000578 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000579 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000580 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000581 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
582#if SK_SUPPORT_GPU
583 return SkNEW(GrGLDistantLight);
584#else
585 SkDEBUGFAIL("Should not call in GPU-less build");
586 return NULL;
587#endif
588 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000589 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
590
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000591 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
592 if (other.type() != kDistant_LightType) {
593 return false;
594 }
595
596 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
597 return INHERITED::isEqual(other) &&
598 fDirection == o.fDirection;
599 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000600
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000601 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000602 fDirection = readPoint3(buffer);
603 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000604
djsollen@google.com08337772012-06-26 14:33:13 +0000605protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000606 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
607 : INHERITED(color), fDirection(direction) {
608 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000609 virtual SkLight* transform(const SkMatrix& matrix) const {
610 return new SkDistantLight(direction(), color());
611 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000612 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000613 writePoint3(fDirection, buffer);
614 }
615
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000616private:
djsollen@google.com08337772012-06-26 14:33:13 +0000617 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618 SkPoint3 fDirection;
619};
620
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000621///////////////////////////////////////////////////////////////////////////////
622
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000623class SkPointLight : public SkLight {
624public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000625 SkPointLight(const SkPoint3& location, SkColor color)
626 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000627
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000628 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
629 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
630 fLocation.fY - SkIntToScalar(y),
631 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
632 direction.normalize();
633 return direction;
634 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000635 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000636 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000637 const SkPoint3& location() const { return fLocation; }
638 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000639#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000640 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000641#else
642 SkDEBUGFAIL("Should not call in GPU-less build");
643 return NULL;
644#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000645 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000646 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000647 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000648 if (other.type() != kPoint_LightType) {
649 return false;
650 }
651 const SkPointLight& o = static_cast<const SkPointLight&>(other);
652 return INHERITED::isEqual(other) &&
653 fLocation == o.fLocation;
654 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000655 virtual SkLight* transform(const SkMatrix& matrix) const {
656 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
657 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000658 // Use X scale and Y scale on Z and average the result
659 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
660 matrix.mapVectors(&locationZ, 1);
661 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000662 return new SkPointLight(location, color());
663 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000664
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000665 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000666 fLocation = readPoint3(buffer);
667 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000668
669protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000670 SkPointLight(const SkPoint3& location, const SkPoint3& color)
671 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000672 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000673 writePoint3(fLocation, buffer);
674 }
675
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000676private:
djsollen@google.com08337772012-06-26 14:33:13 +0000677 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000678 SkPoint3 fLocation;
679};
680
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000681///////////////////////////////////////////////////////////////////////////////
682
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000683class SkSpotLight : public SkLight {
684public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000685 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
686 : INHERITED(color),
687 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000688 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000689 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000690 {
691 fS = target - location;
692 fS.normalize();
693 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000694 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
696 fConeScale = SkScalarInvert(antiAliasThreshold);
697 }
djsollen@google.com08337772012-06-26 14:33:13 +0000698
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000699 virtual SkLight* transform(const SkMatrix& matrix) const {
700 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
701 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000702 // Use X scale and Y scale on Z and average the result
703 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
704 matrix.mapVectors(&locationZ, 1);
705 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000706 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
707 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000708 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
709 matrix.mapVectors(&targetZ, 1);
710 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
711 SkPoint3 s = target - location;
712 s.normalize();
713 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000714 }
715
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000716 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
717 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
718 fLocation.fY - SkIntToScalar(y),
719 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
720 direction.normalize();
721 return direction;
722 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000723 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000724 SkScalar cosAngle = -surfaceToLight.dot(fS);
725 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000726 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000727 }
728 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
729 if (cosAngle < fCosInnerConeAngle) {
730 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000731 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000732 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000733 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000734 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000735 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000736#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000737 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000738#else
739 SkDEBUGFAIL("Should not call in GPU-less build");
740 return NULL;
741#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000742 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000743 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000744 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000745 const SkPoint3& location() const { return fLocation; }
746 const SkPoint3& target() const { return fTarget; }
747 SkScalar specularExponent() const { return fSpecularExponent; }
748 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
749 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
750 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000751 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000752
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000753 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000754 fLocation = readPoint3(buffer);
755 fTarget = readPoint3(buffer);
756 fSpecularExponent = buffer.readScalar();
757 fCosOuterConeAngle = buffer.readScalar();
758 fCosInnerConeAngle = buffer.readScalar();
759 fConeScale = buffer.readScalar();
760 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000761 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
762 SkScalarIsFinite(fCosOuterConeAngle) &&
763 SkScalarIsFinite(fCosInnerConeAngle) &&
764 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000765 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000766protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000767 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
768 : INHERITED(color),
769 fLocation(location),
770 fTarget(target),
771 fSpecularExponent(specularExponent),
772 fCosOuterConeAngle(cosOuterConeAngle),
773 fCosInnerConeAngle(cosInnerConeAngle),
774 fConeScale(coneScale),
775 fS(s)
776 {
777 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000778 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000779 writePoint3(fLocation, buffer);
780 writePoint3(fTarget, buffer);
781 buffer.writeScalar(fSpecularExponent);
782 buffer.writeScalar(fCosOuterConeAngle);
783 buffer.writeScalar(fCosInnerConeAngle);
784 buffer.writeScalar(fConeScale);
785 writePoint3(fS, buffer);
786 }
787
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000788 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000789 if (other.type() != kSpot_LightType) {
790 return false;
791 }
792
793 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
794 return INHERITED::isEqual(other) &&
795 fLocation == o.fLocation &&
796 fTarget == o.fTarget &&
797 fSpecularExponent == o.fSpecularExponent &&
798 fCosOuterConeAngle == o.fCosOuterConeAngle;
799 }
800
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000801private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000802 static const SkScalar kSpecularExponentMin;
803 static const SkScalar kSpecularExponentMax;
804
djsollen@google.com08337772012-06-26 14:33:13 +0000805 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000806 SkPoint3 fLocation;
807 SkPoint3 fTarget;
808 SkScalar fSpecularExponent;
809 SkScalar fCosOuterConeAngle;
810 SkScalar fCosInnerConeAngle;
811 SkScalar fConeScale;
812 SkPoint3 fS;
813};
814
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000815// According to the spec, the specular term should be in the range [1, 128] :
816// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000817const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
818const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000819
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000820///////////////////////////////////////////////////////////////////////////////
821
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000822void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000823 // Write type first, then baseclass, then subclass.
824 buffer.writeInt(this->type());
825 writePoint3(fColor, buffer);
826 this->onFlattenLight(buffer);
827}
828
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000829/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000830 // Read type first.
831 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
832 switch (type) {
833 // Each of these constructors must first call SkLight's, so we'll read the baseclass
834 // then subclass, same order as flattenLight.
835 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
836 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
837 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
838 default:
839 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000840 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000841 return NULL;
842 }
843}
844///////////////////////////////////////////////////////////////////////////////
845
senorblanco9ea3d572014-07-08 09:16:22 -0700846SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
847 SkImageFilter* input, const CropRect* cropRect)
reed9fa60da2014-08-21 07:59:51 -0700848 : INHERITED(1, &input, cropRect)
849 , fLight(SkRef(light))
850 , fSurfaceScale(surfaceScale / 255)
851{}
852
853SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
854 SkColor lightColor,
855 SkScalar surfaceScale,
856 SkScalar kd,
857 SkImageFilter* input,
858 const CropRect* cropRect) {
859 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
860 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000861}
862
reed9fa60da2014-08-21 07:59:51 -0700863SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
864 SkColor lightColor,
865 SkScalar surfaceScale,
866 SkScalar kd,
867 SkImageFilter* input,
868 const CropRect* cropRect) {
869 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
870 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000871}
872
reed9fa60da2014-08-21 07:59:51 -0700873SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
874 const SkPoint3& target,
875 SkScalar specularExponent,
876 SkScalar cutoffAngle,
877 SkColor lightColor,
878 SkScalar surfaceScale,
879 SkScalar kd,
880 SkImageFilter* input,
881 const CropRect* cropRect) {
882 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
883 cutoffAngle, lightColor)));
884 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000885}
886
reed9fa60da2014-08-21 07:59:51 -0700887SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
888 SkColor lightColor,
889 SkScalar surfaceScale,
890 SkScalar ks,
891 SkScalar shine,
892 SkImageFilter* input,
893 const CropRect* cropRect) {
894 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
895 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000896}
897
reed9fa60da2014-08-21 07:59:51 -0700898SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
899 SkColor lightColor,
900 SkScalar surfaceScale,
901 SkScalar ks,
902 SkScalar shine,
903 SkImageFilter* input,
904 const CropRect* cropRect) {
905 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
906 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000907}
908
reed9fa60da2014-08-21 07:59:51 -0700909SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
910 const SkPoint3& target,
911 SkScalar specularExponent,
912 SkScalar cutoffAngle,
913 SkColor lightColor,
914 SkScalar surfaceScale,
915 SkScalar ks,
916 SkScalar shine,
917 SkImageFilter* input,
918 const CropRect* cropRect) {
919 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
920 cutoffAngle, lightColor)));
921 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000922}
923
reed9fa60da2014-08-21 07:59:51 -0700924SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000925
reed9fa60da2014-08-21 07:59:51 -0700926#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000927SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000928 : INHERITED(1, buffer) {
reed9fa60da2014-08-21 07:59:51 -0700929 fLight.reset(SkLight::UnflattenLight(buffer));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000930 fSurfaceScale = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000931 buffer.validate(SkScalarIsFinite(fSurfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000932}
reed9fa60da2014-08-21 07:59:51 -0700933#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000934
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000935void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000936 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000937 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700938 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000939}
940
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000941///////////////////////////////////////////////////////////////////////////////
942
reed9fa60da2014-08-21 07:59:51 -0700943SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
944 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
945 if (NULL == light) {
946 return NULL;
947 }
948 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
949 return NULL;
950 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000951 // According to the spec, kd can be any non-negative number :
952 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700953 if (kd < 0) {
954 return NULL;
955 }
956 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
957}
958
959SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
960 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
961 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000962{
963}
964
reed9fa60da2014-08-21 07:59:51 -0700965#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000966SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000967 : INHERITED(buffer)
968{
969 fKD = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000970 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000971}
reed9fa60da2014-08-21 07:59:51 -0700972#endif
973
974SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
975 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
976 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
977 SkScalar surfaceScale = buffer.readScalar();
978 SkScalar kd = buffer.readScalar();
979 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
980}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000981
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000982void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000983 this->INHERITED::flatten(buffer);
984 buffer.writeScalar(fKD);
985}
986
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000987bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
988 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000989 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000990 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000991 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000992 SkImageFilter* input = getInput(0);
993 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000994 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000995 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000996 return false;
997 }
998
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000999 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001000 return false;
1001 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001002 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001003 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001004 return false;
1005 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001006
1007 if (bounds.width() < 2 || bounds.height() < 2) {
1008 return false;
1009 }
1010
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001011 SkAutoLockPixels alp(src);
1012 if (!src.getPixels()) {
1013 return false;
1014 }
1015
reedc77392e2014-06-02 13:07:26 -07001016 if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001017 return false;
1018 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001019
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001020 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001021
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001022 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001023 offset->fX = bounds.left();
1024 offset->fY = bounds.top();
1025 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001026 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001027 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001028 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001029 break;
1030 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001031 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001032 break;
1033 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001034 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001035 break;
1036 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001037
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001038 return true;
1039}
1040
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001041#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -07001042bool SkDiffuseLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
1043 const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001044 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001045 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001046 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001047 }
1048 return true;
1049}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001050#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001051
1052///////////////////////////////////////////////////////////////////////////////
1053
reed9fa60da2014-08-21 07:59:51 -07001054SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
1055 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
1056 if (NULL == light) {
1057 return NULL;
1058 }
1059 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1060 return NULL;
1061 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001062 // According to the spec, ks can be any non-negative number :
1063 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001064 if (ks < 0) {
1065 return NULL;
1066 }
1067 return SkNEW_ARGS(SkSpecularLightingImageFilter,
1068 (light, surfaceScale, ks, shininess, input, cropRect));
1069}
1070
1071SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
1072 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
1073 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001074 fShininess(shininess)
1075{
1076}
1077
reed9fa60da2014-08-21 07:59:51 -07001078#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001079SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
reed9fa60da2014-08-21 07:59:51 -07001080 : INHERITED(buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001081{
1082 fKS = buffer.readScalar();
1083 fShininess = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001084 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001085 SkScalarIsFinite(fShininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001086}
reed9fa60da2014-08-21 07:59:51 -07001087#endif
1088
1089SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1090 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1091 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1092 SkScalar surfaceScale = buffer.readScalar();
1093 SkScalar ks = buffer.readScalar();
1094 SkScalar shine = buffer.readScalar();
1095 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
1096}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001097
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001098void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001099 this->INHERITED::flatten(buffer);
1100 buffer.writeScalar(fKS);
1101 buffer.writeScalar(fShininess);
1102}
1103
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001104bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1105 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001106 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001107 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001108 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001109 SkImageFilter* input = getInput(0);
1110 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001111 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001112 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001113 return false;
1114 }
1115
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001116 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001117 return false;
1118 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001119
1120 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001121 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001122 return false;
1123 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001124
1125 if (bounds.width() < 2 || bounds.height() < 2) {
1126 return false;
1127 }
1128
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001129 SkAutoLockPixels alp(src);
1130 if (!src.getPixels()) {
1131 return false;
1132 }
1133
reedc77392e2014-06-02 13:07:26 -07001134 if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001135 return false;
1136 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001137
1138 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001139 offset->fX = bounds.left();
1140 offset->fY = bounds.top();
1141 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001142 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001143 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001144 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001145 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001146 break;
1147 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001148 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001149 break;
1150 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001151 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001152 break;
1153 }
1154 return true;
1155}
1156
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001157#if SK_SUPPORT_GPU
bsalomon83d081a2014-07-08 09:56:10 -07001158bool SkSpecularLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
1159 const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001160 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001161 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001162 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001163 }
1164 return true;
1165}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001166#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001167
1168///////////////////////////////////////////////////////////////////////////////
1169
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001170#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001171
1172namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001173SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001174 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1175 SkScalarToFloat(random->nextSScalar1()),
1176 SkScalarToFloat(random->nextSScalar1()));
1177}
1178
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001179SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001180 int type = random->nextULessThan(3);
1181 switch (type) {
1182 case 0: {
1183 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1184 }
1185 case 1: {
1186 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1187 }
1188 case 2: {
1189 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1190 random_point3(random),
1191 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001192 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001193 random->nextU()));
1194 }
1195 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001196 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001197 return NULL;
1198 }
1199}
1200
1201}
1202
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001203class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001204public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001205 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001206 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001207 virtual ~GrGLLightingEffect();
1208
joshualitt30ba4362014-08-21 20:18:45 -07001209 virtual void emitCode(GrGLProgramBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001210 const GrDrawEffect&,
bsalomon63e99f72014-07-21 08:03:14 -07001211 const GrEffectKey&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001212 const char* outputColor,
1213 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001214 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001215 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001216
bsalomon63e99f72014-07-21 08:03:14 -07001217 static inline void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001218
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001219 /**
1220 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1221 */
kkinnunen7510b222014-07-30 00:04:16 -07001222 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001223
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001224protected:
joshualitt30ba4362014-08-21 20:18:45 -07001225 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001226
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001227private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001228 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001230 UniformHandle fImageIncrementUni;
1231 UniformHandle fSurfaceScaleUni;
1232 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001233};
1234
1235///////////////////////////////////////////////////////////////////////////////
1236
1237class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1238public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001239 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001240 const GrDrawEffect& drawEffect);
joshualitt30ba4362014-08-21 20:18:45 -07001241 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
kkinnunen7510b222014-07-30 00:04:16 -07001242 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001243
1244private:
1245 typedef GrGLLightingEffect INHERITED;
1246
bsalomon@google.com032b2212012-07-16 13:36:18 +00001247 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248};
1249
1250///////////////////////////////////////////////////////////////////////////////
1251
1252class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1253public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001254 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001255 const GrDrawEffect& effect);
joshualitt30ba4362014-08-21 20:18:45 -07001256 virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
kkinnunen7510b222014-07-30 00:04:16 -07001257 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001258
1259private:
1260 typedef GrGLLightingEffect INHERITED;
1261
bsalomon@google.com032b2212012-07-16 13:36:18 +00001262 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001263 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001264};
1265
1266///////////////////////////////////////////////////////////////////////////////
1267
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001268GrLightingEffect::GrLightingEffect(GrTexture* texture,
1269 const SkLight* light,
1270 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001271 const SkMatrix& matrix)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001272 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001273 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001274 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001275 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001276 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001277 if (light->requiresFragmentPosition()) {
1278 this->setWillReadFragmentPosition();
1279 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001280}
1281
1282GrLightingEffect::~GrLightingEffect() {
1283 fLight->unref();
1284}
1285
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001286bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001287 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001288 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001289 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001290 fSurfaceScale == s.fSurfaceScale;
1291}
1292
1293///////////////////////////////////////////////////////////////////////////////
1294
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001295GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1296 const SkLight* light,
1297 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001298 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001299 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001300 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001301}
1302
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001303const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1304 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001305}
1306
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001307bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001308 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001309 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001310 this->kd() == s.kd();
1311}
1312
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001313GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001314
bsalomon83d081a2014-07-08 09:56:10 -07001315GrEffect* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1316 GrContext* context,
1317 const GrDrawTargetCaps&,
1318 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001319 SkScalar surfaceScale = random->nextSScalar1();
1320 SkScalar kd = random->nextUScalar1();
1321 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001322 SkMatrix matrix;
1323 for (int i = 0; i < 9; i++) {
1324 matrix[i] = random->nextUScalar1();
1325 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001326 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001327 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001328}
1329
1330
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001331///////////////////////////////////////////////////////////////////////////////
1332
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001333GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001334 const GrDrawEffect& drawEffect)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001335 : INHERITED(factory) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001336 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001337 fLight = m.light()->createGLLight();
1338}
1339
1340GrGLLightingEffect::~GrGLLightingEffect() {
1341 delete fLight;
1342}
1343
joshualitt30ba4362014-08-21 20:18:45 -07001344void GrGLLightingEffect::emitCode(GrGLProgramBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001345 const GrDrawEffect&,
bsalomon63e99f72014-07-21 08:03:14 -07001346 const GrEffectKey& key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001347 const char* outputColor,
1348 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001349 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001350 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001351 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001352 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001353 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001354 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001355 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001356 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001357 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001358 SkString lightFunc;
1359 this->emitLightFunc(builder, &lightFunc);
1360 static const GrGLShaderVar gSobelArgs[] = {
1361 GrGLShaderVar("a", kFloat_GrSLType),
1362 GrGLShaderVar("b", kFloat_GrSLType),
1363 GrGLShaderVar("c", kFloat_GrSLType),
1364 GrGLShaderVar("d", kFloat_GrSLType),
1365 GrGLShaderVar("e", kFloat_GrSLType),
1366 GrGLShaderVar("f", kFloat_GrSLType),
1367 GrGLShaderVar("scale", kFloat_GrSLType),
1368 };
1369 SkString sobelFuncName;
joshualitt30ba4362014-08-21 20:18:45 -07001370 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1371 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1372
1373 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001374 "sobel",
1375 SK_ARRAY_COUNT(gSobelArgs),
1376 gSobelArgs,
1377 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1378 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001379 static const GrGLShaderVar gPointToNormalArgs[] = {
1380 GrGLShaderVar("x", kFloat_GrSLType),
1381 GrGLShaderVar("y", kFloat_GrSLType),
1382 GrGLShaderVar("scale", kFloat_GrSLType),
1383 };
1384 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001385 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001386 "pointToNormal",
1387 SK_ARRAY_COUNT(gPointToNormalArgs),
1388 gPointToNormalArgs,
1389 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1390 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001391
1392 static const GrGLShaderVar gInteriorNormalArgs[] = {
1393 GrGLShaderVar("m", kFloat_GrSLType, 9),
1394 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1395 };
1396 SkString interiorNormalBody;
1397 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1398 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1399 "\t surfaceScale);\n",
1400 pointToNormalName.c_str(),
1401 sobelFuncName.c_str(),
1402 sobelFuncName.c_str());
1403 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001404 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001405 "interiorNormal",
1406 SK_ARRAY_COUNT(gInteriorNormalArgs),
1407 gInteriorNormalArgs,
1408 interiorNormalBody.c_str(),
1409 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001410
joshualitt30ba4362014-08-21 20:18:45 -07001411 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1412 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001413
1414 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1415 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1416
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001417 int index = 0;
1418 for (int dy = -1; dy <= 1; dy++) {
1419 for (int dx = -1; dx <= 1; dx++) {
1420 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001421 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001422 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1423 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1424 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001425 }
1426 }
joshualitt30ba4362014-08-21 20:18:45 -07001427 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001428 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001429 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001430 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001431 fsBuilder->codeAppend(";\n");
1432 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001433 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001434 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001435 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001436 SkString modulate;
1437 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001438 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001439}
1440
bsalomon63e99f72014-07-21 08:03:14 -07001441void GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
1442 const GrGLCaps& caps, GrEffectKeyBuilder* b) {
1443 b->add32(drawEffect.castEffect<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001444}
1445
kkinnunen7510b222014-07-30 00:04:16 -07001446void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001447 const GrDrawEffect& drawEffect) {
1448 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1449 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001450 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001451 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1452 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001453 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001454 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001455}
1456
1457///////////////////////////////////////////////////////////////////////////////
1458
1459///////////////////////////////////////////////////////////////////////////////
1460
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001461GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001462 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001463 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001464}
1465
joshualitt30ba4362014-08-21 20:18:45 -07001466void GrGLDiffuseLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001467 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001468 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001469 kFloat_GrSLType,
1470 "KD",
1471 &kd);
1472
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001473 static const GrGLShaderVar gLightArgs[] = {
1474 GrGLShaderVar("normal", kVec3f_GrSLType),
1475 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1476 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1477 };
1478 SkString lightBody;
1479 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1480 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001481 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1482 "light",
1483 SK_ARRAY_COUNT(gLightArgs),
1484 gLightArgs,
1485 lightBody.c_str(),
1486 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001487}
1488
kkinnunen7510b222014-07-30 00:04:16 -07001489void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001490 const GrDrawEffect& drawEffect) {
kkinnunen7510b222014-07-30 00:04:16 -07001491 INHERITED::setData(pdman, drawEffect);
bsalomon@google.comc7818882013-03-20 19:19:53 +00001492 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001493 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001494}
1495
1496///////////////////////////////////////////////////////////////////////////////
1497
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001498GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1499 const SkLight* light,
1500 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001501 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001502 SkScalar ks,
1503 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001504 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001505 fKS(ks),
1506 fShininess(shininess) {
1507}
1508
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001509const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1510 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001511}
1512
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001513bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001514 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001515 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001516 this->ks() == s.ks() &&
1517 this->shininess() == s.shininess();
1518}
1519
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001520GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001521
bsalomon83d081a2014-07-08 09:56:10 -07001522GrEffect* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1523 GrContext* context,
1524 const GrDrawTargetCaps&,
1525 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001526 SkScalar surfaceScale = random->nextSScalar1();
1527 SkScalar ks = random->nextUScalar1();
1528 SkScalar shininess = random->nextUScalar1();
1529 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001530 SkMatrix matrix;
1531 for (int i = 0; i < 9; i++) {
1532 matrix[i] = random->nextUScalar1();
1533 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001534 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001535 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001536}
1537
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001538///////////////////////////////////////////////////////////////////////////////
1539
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001540GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001541 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001542 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001543}
1544
joshualitt30ba4362014-08-21 20:18:45 -07001545void GrGLSpecularLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001546 const char* ks;
1547 const char* shininess;
1548
joshualitt30ba4362014-08-21 20:18:45 -07001549 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001550 kFloat_GrSLType, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001551 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001552 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001553
1554 static const GrGLShaderVar gLightArgs[] = {
1555 GrGLShaderVar("normal", kVec3f_GrSLType),
1556 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1557 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1558 };
1559 SkString lightBody;
1560 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1561 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001562 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1563 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001564 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1565 "light",
1566 SK_ARRAY_COUNT(gLightArgs),
1567 gLightArgs,
1568 lightBody.c_str(),
1569 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001570}
1571
kkinnunen7510b222014-07-30 00:04:16 -07001572void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001573 const GrDrawEffect& drawEffect) {
kkinnunen7510b222014-07-30 00:04:16 -07001574 INHERITED::setData(pdman, drawEffect);
bsalomon@google.comc7818882013-03-20 19:19:53 +00001575 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001576 pdman.set1f(fKSUni, spec.ks());
1577 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001578}
1579
1580///////////////////////////////////////////////////////////////////////////////
joshualitt30ba4362014-08-21 20:18:45 -07001581void GrGLLight::emitLightColorUniform(GrGLProgramBuilder* builder) {
1582 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001583 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001584}
1585
joshualitt30ba4362014-08-21 20:18:45 -07001586void GrGLLight::emitLightColor(GrGLProgramBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001587 const char *surfaceToLight) {
joshualitt30ba4362014-08-21 20:18:45 -07001588 builder->getFragmentShaderBuilder()->
1589 codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001590}
1591
kkinnunen7510b222014-07-30 00:04:16 -07001592void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001593 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001594 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001595}
1596
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001597///////////////////////////////////////////////////////////////////////////////
1598
kkinnunen7510b222014-07-30 00:04:16 -07001599void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001600 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001601 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001602 SkASSERT(light->type() == SkLight::kDistant_LightType);
1603 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001604 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001605}
1606
joshualitt30ba4362014-08-21 20:18:45 -07001607void GrGLDistantLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001608 const char* dir;
joshualitt30ba4362014-08-21 20:18:45 -07001609 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001610 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001611 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001612}
1613
1614///////////////////////////////////////////////////////////////////////////////
1615
kkinnunen7510b222014-07-30 00:04:16 -07001616void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001617 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001618 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001619 SkASSERT(light->type() == SkLight::kPoint_LightType);
1620 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001621 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001622}
1623
joshualitt30ba4362014-08-21 20:18:45 -07001624void GrGLPointLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001625 const char* loc;
joshualitt30ba4362014-08-21 20:18:45 -07001626 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001627 "LightLocation", &loc);
joshualitt30ba4362014-08-21 20:18:45 -07001628 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1629 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1630 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001631}
1632
1633///////////////////////////////////////////////////////////////////////////////
1634
kkinnunen7510b222014-07-30 00:04:16 -07001635void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001636 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001637 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638 SkASSERT(light->type() == SkLight::kSpot_LightType);
1639 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001640 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1641 pdman.set1f(fExponentUni, spotLight->specularExponent());
1642 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1643 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1644 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1645 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001646}
1647
joshualitt30ba4362014-08-21 20:18:45 -07001648void GrGLSpotLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001649 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001650 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001651 kVec3f_GrSLType, "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001652
1653 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1654 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1655 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001656}
1657
joshualitt30ba4362014-08-21 20:18:45 -07001658void GrGLSpotLight::emitLightColor(GrGLProgramBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001659 const char *surfaceToLight) {
1660
1661 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1662
1663 const char* exponent;
1664 const char* cosInner;
1665 const char* cosOuter;
1666 const char* coneScale;
1667 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001668 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001669 kFloat_GrSLType, "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001670 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001671 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001672 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001673 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001674 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001675 kFloat_GrSLType, "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001676 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001677 kVec3f_GrSLType, "S", &s);
1678
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001679 static const GrGLShaderVar gLightColorArgs[] = {
1680 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1681 };
1682 SkString lightColorBody;
1683 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1684 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1685 lightColorBody.appendf("\t\treturn vec3(0);\n");
1686 lightColorBody.appendf("\t}\n");
1687 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1688 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1689 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1690 color, cosOuter, coneScale);
1691 lightColorBody.appendf("\t}\n");
1692 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt30ba4362014-08-21 20:18:45 -07001693 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1694 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001695 "lightColor",
1696 SK_ARRAY_COUNT(gLightColorArgs),
1697 gLightColorArgs,
1698 lightColorBody.c_str(),
1699 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001700
joshualitt30ba4362014-08-21 20:18:45 -07001701 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001702}
1703
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001704#endif
1705
djsollen@google.com08337772012-06-26 14:33:13 +00001706SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1707 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1708 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001709SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END