blob: 177ba09c8ee55b61a2f3a86d8d41cb94abbd61e1 [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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkFlattenableBuffers.h"
12#include "SkOrderedReadBuffer.h"
13#include "SkOrderedWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000015
16#if SK_SUPPORT_GPU
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000017#include "effects/GrSingleTextureEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000018#include "gl/GrGLEffect.h"
bsalomon@google.com17fc6512012-11-02 21:45:01 +000019#include "gl/GrGLEffectMatrix.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000020#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000021#include "GrTBackendEffectFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000022
23class GrGLDiffuseLightingEffect;
24class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000025
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000026// For brevity
27typedef GrGLUniformManager::UniformHandle UniformHandle;
28static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
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));
35const SkScalar gOneHalf = SkFloatToScalar(0.5f);
36const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
37
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000038#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000039void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000040 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000041 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000042}
43
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000044void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000045 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000046}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000047#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000048
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000049// Shift matrix components to the left, as we advance pixels to the right.
50inline void shiftMatrixLeft(int m[9]) {
51 m[0] = m[1];
52 m[3] = m[4];
53 m[6] = m[7];
54 m[1] = m[2];
55 m[4] = m[5];
56 m[7] = m[8];
57}
58
59class DiffuseLightingType {
60public:
61 DiffuseLightingType(SkScalar kd)
62 : fKD(kd) {}
63 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
64 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
65 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
66 SkPoint3 color(lightColor * colorScale);
67 return SkPackARGB32(255,
68 SkScalarFloorToInt(color.fX),
69 SkScalarFloorToInt(color.fY),
70 SkScalarFloorToInt(color.fZ));
71 }
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);
88 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
89 SkScalarFloorToInt(color.fX),
90 SkScalarFloorToInt(color.fY),
91 SkScalarFloorToInt(color.fZ));
92 }
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.orgbdb1ec42012-07-09 14:29:51 +0000165template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000166 const LightType* l = static_cast<const LightType*>(light);
167 int y = 0;
168 {
169 const SkPMColor* row1 = src.getAddr32(0, 0);
170 const SkPMColor* row2 = src.getAddr32(0, 1);
171 SkPMColor* dptr = dst->getAddr32(0, 0);
172 int m[9];
173 int x = 0;
174 m[4] = SkGetPackedA32(*row1++);
175 m[5] = SkGetPackedA32(*row1++);
176 m[7] = SkGetPackedA32(*row2++);
177 m[8] = SkGetPackedA32(*row2++);
178 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000179 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000180 for (x = 1; x < src.width() - 1; ++x)
181 {
182 shiftMatrixLeft(m);
183 m[5] = SkGetPackedA32(*row1++);
184 m[8] = SkGetPackedA32(*row2++);
185 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000186 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000187 }
188 shiftMatrixLeft(m);
189 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000190 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 }
192
193 for (++y; y < src.height() - 1; ++y) {
194 const SkPMColor* row0 = src.getAddr32(0, y - 1);
195 const SkPMColor* row1 = src.getAddr32(0, y);
196 const SkPMColor* row2 = src.getAddr32(0, y + 1);
197 SkPMColor* dptr = dst->getAddr32(0, y);
198 int m[9];
199 int x = 0;
200 m[1] = SkGetPackedA32(*row0++);
201 m[2] = SkGetPackedA32(*row0++);
202 m[4] = SkGetPackedA32(*row1++);
203 m[5] = SkGetPackedA32(*row1++);
204 m[7] = SkGetPackedA32(*row2++);
205 m[8] = SkGetPackedA32(*row2++);
206 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000207 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000208 for (x = 1; x < src.width() - 1; ++x) {
209 shiftMatrixLeft(m);
210 m[2] = SkGetPackedA32(*row0++);
211 m[5] = SkGetPackedA32(*row1++);
212 m[8] = SkGetPackedA32(*row2++);
213 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000214 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000215 }
216 shiftMatrixLeft(m);
217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000218 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000219 }
220
221 {
222 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
223 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
224 int x = 0;
225 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
226 int m[9];
227 m[1] = SkGetPackedA32(*row0++);
228 m[2] = SkGetPackedA32(*row0++);
229 m[4] = SkGetPackedA32(*row1++);
230 m[5] = SkGetPackedA32(*row1++);
231 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000232 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 for (x = 1; x < src.width() - 1; ++x)
234 {
235 shiftMatrixLeft(m);
236 m[2] = SkGetPackedA32(*row0++);
237 m[5] = SkGetPackedA32(*row1++);
238 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000239 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 }
241 shiftMatrixLeft(m);
242 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000243 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000244 }
245}
246
247SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
248 SkPoint3 point;
249 point.fX = buffer.readScalar();
250 point.fY = buffer.readScalar();
251 point.fZ = buffer.readScalar();
252 return point;
253};
254
255void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
256 buffer.writeScalar(point.fX);
257 buffer.writeScalar(point.fY);
258 buffer.writeScalar(point.fZ);
259};
260
261class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
262public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000263 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
264 SkScalar kd, SkImageFilter* input);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000265 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
266
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000267 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000268 SkScalar kd() const { return fKD; }
269
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270protected:
271 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
272 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
273 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
274 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
275
276
277private:
278 typedef SkLightingImageFilter INHERITED;
279 SkScalar fKD;
280};
281
282class SkSpecularLightingImageFilter : public SkLightingImageFilter {
283public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000284 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000285 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
286
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000287 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000288 SkScalar ks() const { return fKS; }
289 SkScalar shininess() const { return fShininess; }
290
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000291protected:
292 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
293 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
294 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
295 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
296
297private:
298 typedef SkLightingImageFilter INHERITED;
299 SkScalar fKS;
300 SkScalar fShininess;
301};
302
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000303#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000304
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000305class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000306public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000307 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000308 virtual ~GrLightingEffect();
309
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000310 const SkLight* light() const { return fLight; }
311 SkScalar surfaceScale() const { return fSurfaceScale; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000312
313 virtual void getConstantColorComponents(GrColor* color,
314 uint32_t* validFlags) const SK_OVERRIDE {
315 // lighting shaders are complicated. We just throw up our hands.
316 *validFlags = 0;
317 }
318
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000319protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000320 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000321
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000322private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000323 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000324 const SkLight* fLight;
325 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000326};
327
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000328class GrDiffuseLightingEffect : public GrLightingEffect {
329public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000330 static GrEffectRef* Create(GrTexture* texture,
331 const SkLight* light,
332 SkScalar surfaceScale,
333 SkScalar kd) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000334 AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
335 light,
336 surfaceScale,
337 kd)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000338 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000339 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000340
341 static const char* Name() { return "DiffuseLighting"; }
342
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000343 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000344
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000345 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000346 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000347
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000348private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000349 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000350
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000351 GrDiffuseLightingEffect(GrTexture* texture,
352 const SkLight* light,
353 SkScalar surfaceScale,
354 SkScalar kd);
355
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000356 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000357 typedef GrLightingEffect INHERITED;
358 SkScalar fKD;
359};
360
361class GrSpecularLightingEffect : public GrLightingEffect {
362public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000363 static GrEffectRef* Create(GrTexture* texture,
364 const SkLight* light,
365 SkScalar surfaceScale,
366 SkScalar ks,
367 SkScalar shininess) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000368 AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
369 light,
370 surfaceScale,
371 ks,
372 shininess)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000373 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000374 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000375 static const char* Name() { return "SpecularLighting"; }
376
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000377 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000378
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000379 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000380 SkScalar ks() const { return fKS; }
381 SkScalar shininess() const { return fShininess; }
382
383private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000384 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000385
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000386 GrSpecularLightingEffect(GrTexture* texture,
387 const SkLight* light,
388 SkScalar surfaceScale,
389 SkScalar ks,
390 SkScalar shininess);
391
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000392 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000393 typedef GrLightingEffect INHERITED;
394 SkScalar fKS;
395 SkScalar fShininess;
396};
397
398///////////////////////////////////////////////////////////////////////////////
399
400class GrGLLight {
401public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000402 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000403
404 /**
405 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
406 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
407 */
408 void emitLightColorUniform(GrGLShaderBuilder*);
409
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000410 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000411 * These two functions are called from GrGLLightingEffect's emitCode() function.
412 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
413 * the light. The expression will be used in the FS. emitLightColor writes an expression into
414 * the FS that is the color of the light. Either function may add functions and/or uniforms to
415 * the FS. The default of emitLightColor appends the name of the constant light color uniform
416 * and so this function only needs to be overridden if the light color varies spatially.
417 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000418 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000419 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
420
421 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
422 // INHERITED::setData().
bsalomon@google.com706f6682012-10-23 14:53:55 +0000423 virtual void setData(const GrGLUniformManager&, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000424
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000425protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000426 /**
427 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
428 * function.
429 */
430 UniformHandle lightColorUni() const { return fColorUni; }
431
432private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000433 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000434
435 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000436};
437
438///////////////////////////////////////////////////////////////////////////////
439
440class GrGLDistantLight : public GrGLLight {
441public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000442 virtual ~GrGLDistantLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000443 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000444 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000445private:
446 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000447 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000448};
449
450///////////////////////////////////////////////////////////////////////////////
451
452class GrGLPointLight : public GrGLLight {
453public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000454 virtual ~GrGLPointLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000455 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000456 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000457private:
458 typedef GrGLLight INHERITED;
459 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000460 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000461};
462
463///////////////////////////////////////////////////////////////////////////////
464
465class GrGLSpotLight : public GrGLLight {
466public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000467 virtual ~GrGLSpotLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000468 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000469 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000470 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000471private:
472 typedef GrGLLight INHERITED;
473
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000474 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000475 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000476 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000477 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000478 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000479 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000480 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000481};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000482#else
483
484class GrGLLight;
485
486#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000487
488};
489
490///////////////////////////////////////////////////////////////////////////////
491
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000492class SkLight : public SkFlattenable {
493public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000494 SK_DECLARE_INST_COUNT(SkLight)
495
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000496 enum LightType {
497 kDistant_LightType,
498 kPoint_LightType,
499 kSpot_LightType,
500 };
501 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000502 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000503 virtual GrGLLight* createGLLight() const = 0;
504 virtual bool isEqual(const SkLight& other) const {
505 return fColor == other.fColor;
506 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000507
djsollen@google.com08337772012-06-26 14:33:13 +0000508protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000509 SkLight(SkColor color)
510 : fColor(SkIntToScalar(SkColorGetR(color)),
511 SkIntToScalar(SkColorGetG(color)),
512 SkIntToScalar(SkColorGetB(color))) {}
513 SkLight(SkFlattenableReadBuffer& buffer)
514 : INHERITED(buffer) {
515 fColor = readPoint3(buffer);
516 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000517 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000518 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000519 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000520 }
djsollen@google.com08337772012-06-26 14:33:13 +0000521
522private:
523 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000524 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525};
526
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000527SK_DEFINE_INST_COUNT(SkLight)
528
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529///////////////////////////////////////////////////////////////////////////////
530
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000531class SkDistantLight : public SkLight {
532public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000533 SkDistantLight(const SkPoint3& direction, SkColor color)
534 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000535 }
djsollen@google.com08337772012-06-26 14:33:13 +0000536
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000537 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
538 return fDirection;
539 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000540 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000541 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000542 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000543 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
544#if SK_SUPPORT_GPU
545 return SkNEW(GrGLDistantLight);
546#else
547 SkDEBUGFAIL("Should not call in GPU-less build");
548 return NULL;
549#endif
550 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000551 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
552 if (other.type() != kDistant_LightType) {
553 return false;
554 }
555
556 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
557 return INHERITED::isEqual(other) &&
558 fDirection == o.fDirection;
559 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560
561 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
562
djsollen@google.com08337772012-06-26 14:33:13 +0000563protected:
564 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
565 fDirection = readPoint3(buffer);
566 }
567 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
568 INHERITED::flatten(buffer);
569 writePoint3(fDirection, buffer);
570 }
571
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000572private:
djsollen@google.com08337772012-06-26 14:33:13 +0000573 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000574 SkPoint3 fDirection;
575};
576
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000577///////////////////////////////////////////////////////////////////////////////
578
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000579class SkPointLight : public SkLight {
580public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000581 SkPointLight(const SkPoint3& location, SkColor color)
582 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000583
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000584 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
585 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
586 fLocation.fY - SkIntToScalar(y),
587 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
588 direction.normalize();
589 return direction;
590 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000591 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000592 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000593 const SkPoint3& location() const { return fLocation; }
594 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000595#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000596 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000597#else
598 SkDEBUGFAIL("Should not call in GPU-less build");
599 return NULL;
600#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000601 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000602 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000603 if (other.type() != kPoint_LightType) {
604 return false;
605 }
606 const SkPointLight& o = static_cast<const SkPointLight&>(other);
607 return INHERITED::isEqual(other) &&
608 fLocation == o.fLocation;
609 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000610
611 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
612
djsollen@google.com08337772012-06-26 14:33:13 +0000613protected:
614 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
615 fLocation = readPoint3(buffer);
616 }
617 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
618 INHERITED::flatten(buffer);
619 writePoint3(fLocation, buffer);
620 }
621
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000622private:
djsollen@google.com08337772012-06-26 14:33:13 +0000623 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000624 SkPoint3 fLocation;
625};
626
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000627///////////////////////////////////////////////////////////////////////////////
628
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000629class SkSpotLight : public SkLight {
630public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000631 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
632 : INHERITED(color),
633 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000634 fTarget(target),
635 fSpecularExponent(specularExponent)
636 {
637 fS = target - location;
638 fS.normalize();
639 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
640 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
641 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
642 fConeScale = SkScalarInvert(antiAliasThreshold);
643 }
djsollen@google.com08337772012-06-26 14:33:13 +0000644
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000645 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
646 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
647 fLocation.fY - SkIntToScalar(y),
648 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
649 direction.normalize();
650 return direction;
651 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000652 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000653 SkScalar cosAngle = -surfaceToLight.dot(fS);
654 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000655 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000656 }
657 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
658 if (cosAngle < fCosInnerConeAngle) {
659 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000660 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000661 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000662 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000663 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000664 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000665#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000666 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000667#else
668 SkDEBUGFAIL("Should not call in GPU-less build");
669 return NULL;
670#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000671 }
djsollen@google.com08337772012-06-26 14:33:13 +0000672 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000673 const SkPoint3& location() const { return fLocation; }
674 const SkPoint3& target() const { return fTarget; }
675 SkScalar specularExponent() const { return fSpecularExponent; }
676 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
677 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
678 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000679 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000680
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000681 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
682
djsollen@google.com08337772012-06-26 14:33:13 +0000683protected:
684 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
685 fLocation = readPoint3(buffer);
686 fTarget = readPoint3(buffer);
687 fSpecularExponent = buffer.readScalar();
688 fCosOuterConeAngle = buffer.readScalar();
689 fCosInnerConeAngle = buffer.readScalar();
690 fConeScale = buffer.readScalar();
691 fS = readPoint3(buffer);
692 }
693 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
694 INHERITED::flatten(buffer);
695 writePoint3(fLocation, buffer);
696 writePoint3(fTarget, buffer);
697 buffer.writeScalar(fSpecularExponent);
698 buffer.writeScalar(fCosOuterConeAngle);
699 buffer.writeScalar(fCosInnerConeAngle);
700 buffer.writeScalar(fConeScale);
701 writePoint3(fS, buffer);
702 }
703
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000704 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000705 if (other.type() != kSpot_LightType) {
706 return false;
707 }
708
709 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
710 return INHERITED::isEqual(other) &&
711 fLocation == o.fLocation &&
712 fTarget == o.fTarget &&
713 fSpecularExponent == o.fSpecularExponent &&
714 fCosOuterConeAngle == o.fCosOuterConeAngle;
715 }
716
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000717private:
djsollen@google.com08337772012-06-26 14:33:13 +0000718 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000719 SkPoint3 fLocation;
720 SkPoint3 fTarget;
721 SkScalar fSpecularExponent;
722 SkScalar fCosOuterConeAngle;
723 SkScalar fCosInnerConeAngle;
724 SkScalar fConeScale;
725 SkPoint3 fS;
726};
727
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000728///////////////////////////////////////////////////////////////////////////////
729
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000730SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input)
731 : INHERITED(input),
732 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
734{
735 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000736 // our caller knows that we take ownership of the light, so we don't
737 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738}
739
740SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000742 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000743 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000744 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
745 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000746}
747
748SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000749 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000750 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000751 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000752 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
753 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000754}
755
756SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000757 const SkPoint3& location, const SkPoint3& target,
758 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000759 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
760 SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000761 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000762 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
763 cutoffAngle, lightColor)),
764 surfaceScale, kd, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000765}
766
767SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000768 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000769 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000770 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000771 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
772 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000773}
774
775SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000776 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000777 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000778 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000779 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
780 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000781}
782
783SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000784 const SkPoint3& location, const SkPoint3& target,
785 SkScalar specularExponent, SkScalar cutoffAngle,
786 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000787 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000788 return SkNEW_ARGS(SkSpecularLightingImageFilter,
789 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000790 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000791}
792
793SkLightingImageFilter::~SkLightingImageFilter() {
794 fLight->unref();
795}
796
797SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
798 : INHERITED(buffer)
799{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000800 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000801 fSurfaceScale = buffer.readScalar();
802}
803
804void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
805 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000806 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000807 buffer.writeScalar(fSurfaceScale);
808}
809
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000810///////////////////////////////////////////////////////////////////////////////
811
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000812SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input)
813 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000814 fKD(kd)
815{
816}
817
818SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
819 : INHERITED(buffer)
820{
821 fKD = buffer.readScalar();
822}
823
824void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
825 this->INHERITED::flatten(buffer);
826 buffer.writeScalar(fKD);
827}
828
829bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
830 const SkBitmap& src,
831 const SkMatrix&,
832 SkBitmap* dst,
833 SkIPoint*) {
834 if (src.config() != SkBitmap::kARGB_8888_Config) {
835 return false;
836 }
837 SkAutoLockPixels alp(src);
838 if (!src.getPixels()) {
839 return false;
840 }
841 if (src.width() < 2 || src.height() < 2) {
842 return false;
843 }
844 dst->setConfig(src.config(), src.width(), src.height());
845 dst->allocPixels();
846
847 DiffuseLightingType lightingType(fKD);
848 switch (light()->type()) {
849 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000850 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851 break;
852 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000853 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000854 break;
855 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000856 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000857 break;
858 }
859 return true;
860}
861
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000862bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect,
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000863 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000864#if SK_SUPPORT_GPU
bsalomon@google.com021fc732012-10-25 12:47:42 +0000865 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000866 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000867 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000868 }
869 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000870#else
871 SkDEBUGFAIL("Should not call in GPU-less build");
872 return false;
873#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000874}
875
876///////////////////////////////////////////////////////////////////////////////
877
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000878SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input)
879 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000880 fKS(ks),
881 fShininess(shininess)
882{
883}
884
885SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
886 : INHERITED(buffer)
887{
888 fKS = buffer.readScalar();
889 fShininess = buffer.readScalar();
890}
891
892void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
893 this->INHERITED::flatten(buffer);
894 buffer.writeScalar(fKS);
895 buffer.writeScalar(fShininess);
896}
897
898bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
899 const SkBitmap& src,
900 const SkMatrix&,
901 SkBitmap* dst,
902 SkIPoint*) {
903 if (src.config() != SkBitmap::kARGB_8888_Config) {
904 return false;
905 }
906 SkAutoLockPixels alp(src);
907 if (!src.getPixels()) {
908 return false;
909 }
910 if (src.width() < 2 || src.height() < 2) {
911 return false;
912 }
913 dst->setConfig(src.config(), src.width(), src.height());
914 dst->allocPixels();
915
916 SpecularLightingType lightingType(fKS, fShininess);
917 switch (light()->type()) {
918 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000919 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000920 break;
921 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000922 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 break;
924 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000925 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000926 break;
927 }
928 return true;
929}
930
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000931bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect,
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000932 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000933#if SK_SUPPORT_GPU
bsalomon@google.com021fc732012-10-25 12:47:42 +0000934 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000935 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000936 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000937 }
938 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000939#else
940 SkDEBUGFAIL("Should not call in GPU-less build");
941 return false;
942#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000943}
944
945///////////////////////////////////////////////////////////////////////////////
946
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000947#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000948
949namespace {
bsalomon@google.com73a96942013-02-13 16:31:19 +0000950SkPoint3 random_point3(SkMWCRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000951 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
952 SkScalarToFloat(random->nextSScalar1()),
953 SkScalarToFloat(random->nextSScalar1()));
954}
955
bsalomon@google.com73a96942013-02-13 16:31:19 +0000956SkLight* create_random_light(SkMWCRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000957 int type = random->nextULessThan(3);
958 switch (type) {
959 case 0: {
960 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
961 }
962 case 1: {
963 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
964 }
965 case 2: {
966 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
967 random_point3(random),
968 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000969 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000970 random->nextU()));
971 }
972 default:
973 GrCrash();
974 return NULL;
975 }
976}
977
978}
979
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000980class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000981public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000982 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000983 const GrEffectRef& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000984 virtual ~GrGLLightingEffect();
985
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000986 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000987 const GrEffectStage&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000988 EffectKey,
989 const char* vertexCoords,
990 const char* outputColor,
991 const char* inputColor,
992 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000993
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000994 static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000995
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000996 /**
997 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
998 */
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000999 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001001protected:
1002 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1003
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001004private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001005 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001006
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001007 UniformHandle fImageIncrementUni;
1008 UniformHandle fSurfaceScaleUni;
1009 GrGLLight* fLight;
1010 GrGLEffectMatrix fEffectMatrix;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001011};
1012
1013///////////////////////////////////////////////////////////////////////////////
1014
1015class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1016public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001017 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +00001018 const GrEffectRef& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001019 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001020 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001021
1022private:
1023 typedef GrGLLightingEffect INHERITED;
1024
bsalomon@google.com032b2212012-07-16 13:36:18 +00001025 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001026};
1027
1028///////////////////////////////////////////////////////////////////////////////
1029
1030class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1031public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001032 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +00001033 const GrEffectRef& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001034 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001035 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001036
1037private:
1038 typedef GrGLLightingEffect INHERITED;
1039
bsalomon@google.com032b2212012-07-16 13:36:18 +00001040 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001041 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001042};
1043
1044///////////////////////////////////////////////////////////////////////////////
1045
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001046GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001047 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001048 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001049 , fSurfaceScale(surfaceScale) {
1050 fLight->ref();
1051}
1052
1053GrLightingEffect::~GrLightingEffect() {
1054 fLight->unref();
1055}
1056
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001057bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001058 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001059 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001060 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001061 fSurfaceScale == s.fSurfaceScale;
1062}
1063
1064///////////////////////////////////////////////////////////////////////////////
1065
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001066GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1067 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001068}
1069
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001070const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1071 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001072}
1073
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001074bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001075 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001076 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001077 this->kd() == s.kd();
1078}
1079
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001080GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001081
bsalomon@google.com73a96942013-02-13 16:31:19 +00001082GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkMWCRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001083 GrContext* context,
1084 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001085 SkScalar surfaceScale = random->nextSScalar1();
1086 SkScalar kd = random->nextUScalar1();
1087 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001088 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1089 light, surfaceScale, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001090}
1091
1092
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001093///////////////////////////////////////////////////////////////////////////////
1094
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001095GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +00001096 const GrEffectRef& effect)
bsalomon@google.com374e7592012-10-23 17:30:45 +00001097 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001098 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001099 , fSurfaceScaleUni(kInvalidUniformHandle) {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001100 const GrLightingEffect& m = CastEffect<GrLightingEffect>(effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001101 fLight = m.light()->createGLLight();
1102}
1103
1104GrGLLightingEffect::~GrGLLightingEffect() {
1105 delete fLight;
1106}
1107
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001108void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001109 const GrEffectStage&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001110 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001111 const char* vertexCoords,
1112 const char* outputColor,
1113 const char* inputColor,
1114 const TextureSamplerArray& samplers) {
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001115 const char* coords;
1116 fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
1117
bsalomon@google.com032b2212012-07-16 13:36:18 +00001118 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1119 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001120 "ImageIncrement");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001121 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1122 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001123 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001124 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001125 SkString lightFunc;
1126 this->emitLightFunc(builder, &lightFunc);
1127 static const GrGLShaderVar gSobelArgs[] = {
1128 GrGLShaderVar("a", kFloat_GrSLType),
1129 GrGLShaderVar("b", kFloat_GrSLType),
1130 GrGLShaderVar("c", kFloat_GrSLType),
1131 GrGLShaderVar("d", kFloat_GrSLType),
1132 GrGLShaderVar("e", kFloat_GrSLType),
1133 GrGLShaderVar("f", kFloat_GrSLType),
1134 GrGLShaderVar("scale", kFloat_GrSLType),
1135 };
1136 SkString sobelFuncName;
1137 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1138 kFloat_GrSLType,
1139 "sobel",
1140 SK_ARRAY_COUNT(gSobelArgs),
1141 gSobelArgs,
1142 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1143 &sobelFuncName);
1144 static const GrGLShaderVar gPointToNormalArgs[] = {
1145 GrGLShaderVar("x", kFloat_GrSLType),
1146 GrGLShaderVar("y", kFloat_GrSLType),
1147 GrGLShaderVar("scale", kFloat_GrSLType),
1148 };
1149 SkString pointToNormalName;
1150 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1151 kVec3f_GrSLType,
1152 "pointToNormal",
1153 SK_ARRAY_COUNT(gPointToNormalArgs),
1154 gPointToNormalArgs,
bsalomon@google.com706f6682012-10-23 14:53:55 +00001155 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001156 &pointToNormalName);
1157
1158 static const GrGLShaderVar gInteriorNormalArgs[] = {
1159 GrGLShaderVar("m", kFloat_GrSLType, 9),
1160 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1161 };
1162 SkString interiorNormalBody;
1163 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1164 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1165 "\t surfaceScale);\n",
1166 pointToNormalName.c_str(),
1167 sobelFuncName.c_str(),
1168 sobelFuncName.c_str());
1169 SkString interiorNormalName;
1170 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1171 kVec3f_GrSLType,
1172 "interiorNormal",
1173 SK_ARRAY_COUNT(gInteriorNormalArgs),
1174 gInteriorNormalArgs,
1175 interiorNormalBody.c_str(),
1176 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001177
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001178 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords);
1179 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001180
1181 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1182 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1183
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001184 int index = 0;
1185 for (int dy = -1; dy <= 1; dy++) {
1186 for (int dx = -1; dx <= 1; dx++) {
1187 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001188 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001189 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
1190 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
1191 samplers[0],
1192 texCoords.c_str());
1193 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194 }
1195 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001196 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001197 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001198 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001199 fLight->emitSurfaceToLight(builder, arg.c_str());
1200 builder->fsCodeAppend(";\n");
1201 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1202 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001203 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001204 builder->fsCodeAppend(");\n");
1205 SkString modulate;
1206 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1207 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001208}
1209
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001210GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrEffectStage& s,
1211 const GrGLCaps& caps) {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001212 const GrLightingEffect& effect = GetEffectFromStage<GrLightingEffect>(s);
1213 EffectKey key = effect.light()->type();
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001214 key <<= GrGLEffectMatrix::kKeyBits;
1215 EffectKey matrixKey = GrGLEffectMatrix::GenKey(effect.getMatrix(),
1216 s.getCoordChangeMatrix(),
1217 effect.texture(0));
1218 return key | matrixKey;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001219}
1220
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001221void GrGLLightingEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001222 const GrLightingEffect& effect = GetEffectFromStage<GrLightingEffect>(stage);
bsalomon@google.com2d0bade2012-10-26 19:01:17 +00001223 GrTexture* texture = effect.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001224 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001225 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1226 uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
bsalomon@google.com706f6682012-10-23 14:53:55 +00001227 fLight->setData(uman, effect.light());
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001228 fEffectMatrix.setData(uman,
1229 effect.getMatrix(),
1230 stage.getCoordChangeMatrix(),
1231 effect.texture(0));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001232}
1233
1234///////////////////////////////////////////////////////////////////////////////
1235
1236///////////////////////////////////////////////////////////////////////////////
1237
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001238GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +00001239 const GrEffectRef& effect)
bsalomon@google.com021fc732012-10-25 12:47:42 +00001240 : INHERITED(factory, effect)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001241 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001242}
1243
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001244void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001245 const char* kd;
1246 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1247 kFloat_GrSLType,
1248 "KD",
1249 &kd);
1250
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001251 static const GrGLShaderVar gLightArgs[] = {
1252 GrGLShaderVar("normal", kVec3f_GrSLType),
1253 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1254 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1255 };
1256 SkString lightBody;
1257 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1258 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1259 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1260 kVec4f_GrSLType,
1261 "light",
1262 SK_ARRAY_COUNT(gLightArgs),
1263 gLightArgs,
1264 lightBody.c_str(),
1265 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001266}
1267
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001268void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
1269 const GrEffectStage& stage) {
1270 INHERITED::setData(uman, stage);
bsalomon@google.com6340a412013-01-22 19:55:59 +00001271 const GrDiffuseLightingEffect& effect = GetEffectFromStage<GrDiffuseLightingEffect>(stage);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001272 uman.set1f(fKDUni, effect.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001273}
1274
1275///////////////////////////////////////////////////////////////////////////////
1276
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001277GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1278 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001279 fKS(ks),
1280 fShininess(shininess) {
1281}
1282
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001283const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1284 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001285}
1286
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001287bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001288 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001289 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001290 this->ks() == s.ks() &&
1291 this->shininess() == s.shininess();
1292}
1293
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001294GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001295
bsalomon@google.com73a96942013-02-13 16:31:19 +00001296GrEffectRef* GrSpecularLightingEffect::TestCreate(SkMWCRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001297 GrContext* context,
1298 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001299 SkScalar surfaceScale = random->nextSScalar1();
1300 SkScalar ks = random->nextUScalar1();
1301 SkScalar shininess = random->nextUScalar1();
1302 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001303 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1304 light, surfaceScale, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001305}
1306
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001307///////////////////////////////////////////////////////////////////////////////
1308
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001309GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +00001310 const GrEffectRef& effect)
bsalomon@google.com021fc732012-10-25 12:47:42 +00001311 : GrGLLightingEffect(factory, effect)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001312 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001313 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001314}
1315
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001316void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001317 const char* ks;
1318 const char* shininess;
1319
1320 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1321 kFloat_GrSLType, "KS", &ks);
1322 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1323 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001324
1325 static const GrGLShaderVar gLightArgs[] = {
1326 GrGLShaderVar("normal", kVec3f_GrSLType),
1327 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1328 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1329 };
1330 SkString lightBody;
1331 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1332 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001333 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1334 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001335 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1336 kVec4f_GrSLType,
1337 "light",
1338 SK_ARRAY_COUNT(gLightArgs),
1339 gLightArgs,
1340 lightBody.c_str(),
1341 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001342}
1343
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001344void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001345 const GrEffectStage& stage) {
1346 INHERITED::setData(uman, stage);
bsalomon@google.com6340a412013-01-22 19:55:59 +00001347 const GrSpecularLightingEffect& effect = GetEffectFromStage<GrSpecularLightingEffect>(stage);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001348 uman.set1f(fKSUni, effect.ks());
1349 uman.set1f(fShininessUni, effect.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001350}
1351
1352///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001353void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001354 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001355 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001356}
1357
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001358void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1359 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001360 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001361}
1362
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001363void GrGLLight::setData(const GrGLUniformManager& uman,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001364 const SkLight* light) const {
1365 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001366}
1367
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001368///////////////////////////////////////////////////////////////////////////////
1369
bsalomon@google.com706f6682012-10-23 14:53:55 +00001370void GrGLDistantLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
1371 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001372 SkASSERT(light->type() == SkLight::kDistant_LightType);
1373 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001374 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001375}
1376
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001377void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001378 const char* dir;
1379 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1380 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001381 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001382}
1383
1384///////////////////////////////////////////////////////////////////////////////
1385
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001386void GrGLPointLight::setData(const GrGLUniformManager& uman,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001387 const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001388 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001389 SkASSERT(light->type() == SkLight::kPoint_LightType);
1390 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001391 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001392}
1393
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001394void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001395 const char* loc;
1396 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1397 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001398 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001399}
1400
1401///////////////////////////////////////////////////////////////////////////////
1402
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001403void GrGLSpotLight::setData(const GrGLUniformManager& uman,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001404 const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001405 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001406 SkASSERT(light->type() == SkLight::kSpot_LightType);
1407 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001408 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001409 uman.set1f(fExponentUni, spotLight->specularExponent());
1410 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1411 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1412 uman.set1f(fConeScaleUni, spotLight->coneScale());
1413 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001414}
1415
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001416void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001417 const char* location;
1418 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1419 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001420 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1421 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001422}
1423
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001424void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1425 const char *surfaceToLight) {
1426
1427 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1428
1429 const char* exponent;
1430 const char* cosInner;
1431 const char* cosOuter;
1432 const char* coneScale;
1433 const char* s;
1434 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1435 kFloat_GrSLType, "Exponent", &exponent);
1436 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1437 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1438 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1439 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1440 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1441 kFloat_GrSLType, "ConeScale", &coneScale);
1442 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1443 kVec3f_GrSLType, "S", &s);
1444
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001445 static const GrGLShaderVar gLightColorArgs[] = {
1446 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1447 };
1448 SkString lightColorBody;
1449 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1450 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1451 lightColorBody.appendf("\t\treturn vec3(0);\n");
1452 lightColorBody.appendf("\t}\n");
1453 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1454 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1455 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1456 color, cosOuter, coneScale);
1457 lightColorBody.appendf("\t}\n");
1458 lightColorBody.appendf("\treturn %s;\n", color);
1459 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1460 kVec3f_GrSLType,
1461 "lightColor",
1462 SK_ARRAY_COUNT(gLightColorArgs),
1463 gLightColorArgs,
1464 lightColorBody.c_str(),
1465 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001466
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001467 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001468}
1469
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001470#endif
1471
djsollen@google.com08337772012-06-26 14:33:13 +00001472SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1473 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1474 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1475 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1476 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1477 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1478SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END