blob: bb2927bbf402809970604e270ef53268645df5ec [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
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000267#if SK_SUPPORT_GPU
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000268 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000269#endif
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000270 SkScalar kd() const { return fKD; }
271
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000272protected:
273 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
274 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
275 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
276 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
277
278
279private:
280 typedef SkLightingImageFilter INHERITED;
281 SkScalar fKD;
282};
283
284class SkSpecularLightingImageFilter : public SkLightingImageFilter {
285public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000286 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000287 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
288
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000289#if SK_SUPPORT_GPU
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000290 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000291#endif
292
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000293 SkScalar ks() const { return fKS; }
294 SkScalar shininess() const { return fShininess; }
295
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000296protected:
297 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
298 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
299 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
300 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
301
302private:
303 typedef SkLightingImageFilter INHERITED;
304 SkScalar fKS;
305 SkScalar fShininess;
306};
307
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000308#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000309
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000310class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000311public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000312 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000313 virtual ~GrLightingEffect();
314
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000315 const SkLight* light() const { return fLight; }
316 SkScalar surfaceScale() const { return fSurfaceScale; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000317
318 virtual void getConstantColorComponents(GrColor* color,
319 uint32_t* validFlags) const SK_OVERRIDE {
320 // lighting shaders are complicated. We just throw up our hands.
321 *validFlags = 0;
322 }
323
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000324protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000325 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000326
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000327private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000328 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000329 const SkLight* fLight;
330 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000331};
332
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000333class GrDiffuseLightingEffect : public GrLightingEffect {
334public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000335 static GrEffectRef* Create(GrTexture* texture,
336 const SkLight* light,
337 SkScalar surfaceScale,
338 SkScalar kd) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000339 AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
340 light,
341 surfaceScale,
342 kd)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000343 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000344 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000345
346 static const char* Name() { return "DiffuseLighting"; }
347
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000348 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000349
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000350 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000351 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000352
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000353private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000354 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000355
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000356 GrDiffuseLightingEffect(GrTexture* texture,
357 const SkLight* light,
358 SkScalar surfaceScale,
359 SkScalar kd);
360
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000361 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000362 typedef GrLightingEffect INHERITED;
363 SkScalar fKD;
364};
365
366class GrSpecularLightingEffect : public GrLightingEffect {
367public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000368 static GrEffectRef* Create(GrTexture* texture,
369 const SkLight* light,
370 SkScalar surfaceScale,
371 SkScalar ks,
372 SkScalar shininess) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000373 AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
374 light,
375 surfaceScale,
376 ks,
377 shininess)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000378 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000379 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000380 static const char* Name() { return "SpecularLighting"; }
381
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000382 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000383
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000384 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000385 SkScalar ks() const { return fKS; }
386 SkScalar shininess() const { return fShininess; }
387
388private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000389 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000390
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000391 GrSpecularLightingEffect(GrTexture* texture,
392 const SkLight* light,
393 SkScalar surfaceScale,
394 SkScalar ks,
395 SkScalar shininess);
396
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000397 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000398 typedef GrLightingEffect INHERITED;
399 SkScalar fKS;
400 SkScalar fShininess;
401};
402
403///////////////////////////////////////////////////////////////////////////////
404
405class GrGLLight {
406public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000407 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000408
409 /**
410 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
411 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
412 */
413 void emitLightColorUniform(GrGLShaderBuilder*);
414
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000415 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000416 * These two functions are called from GrGLLightingEffect's emitCode() function.
417 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
418 * the light. The expression will be used in the FS. emitLightColor writes an expression into
419 * the FS that is the color of the light. Either function may add functions and/or uniforms to
420 * the FS. The default of emitLightColor appends the name of the constant light color uniform
421 * and so this function only needs to be overridden if the light color varies spatially.
422 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000423 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000424 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
425
426 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
427 // INHERITED::setData().
bsalomon@google.com706f6682012-10-23 14:53:55 +0000428 virtual void setData(const GrGLUniformManager&, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000429
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000430protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000431 /**
432 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
433 * function.
434 */
435 UniformHandle lightColorUni() const { return fColorUni; }
436
437private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000438 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000439
440 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000441};
442
443///////////////////////////////////////////////////////////////////////////////
444
445class GrGLDistantLight : public GrGLLight {
446public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000447 virtual ~GrGLDistantLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000448 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000449 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000450private:
451 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000452 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000453};
454
455///////////////////////////////////////////////////////////////////////////////
456
457class GrGLPointLight : public GrGLLight {
458public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000459 virtual ~GrGLPointLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000460 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000461 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000462private:
463 typedef GrGLLight INHERITED;
464 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000465 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000466};
467
468///////////////////////////////////////////////////////////////////////////////
469
470class GrGLSpotLight : public GrGLLight {
471public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000472 virtual ~GrGLSpotLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000473 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000474 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000475 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000476private:
477 typedef GrGLLight INHERITED;
478
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000479 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000480 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000481 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000482 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000483 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000484 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000485 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000486};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000487#else
488
489class GrGLLight;
490
491#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492
493};
494
495///////////////////////////////////////////////////////////////////////////////
496
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000497class SkLight : public SkFlattenable {
498public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000499 SK_DECLARE_INST_COUNT(SkLight)
500
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501 enum LightType {
502 kDistant_LightType,
503 kPoint_LightType,
504 kSpot_LightType,
505 };
506 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000507 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508 virtual GrGLLight* createGLLight() const = 0;
509 virtual bool isEqual(const SkLight& other) const {
510 return fColor == other.fColor;
511 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512
djsollen@google.com08337772012-06-26 14:33:13 +0000513protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000514 SkLight(SkColor color)
515 : fColor(SkIntToScalar(SkColorGetR(color)),
516 SkIntToScalar(SkColorGetG(color)),
517 SkIntToScalar(SkColorGetB(color))) {}
518 SkLight(SkFlattenableReadBuffer& buffer)
519 : INHERITED(buffer) {
520 fColor = readPoint3(buffer);
521 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000522 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000523 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000524 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525 }
djsollen@google.com08337772012-06-26 14:33:13 +0000526
527private:
528 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000529 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000530};
531
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000532SK_DEFINE_INST_COUNT(SkLight)
533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534///////////////////////////////////////////////////////////////////////////////
535
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000536class SkDistantLight : public SkLight {
537public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000538 SkDistantLight(const SkPoint3& direction, SkColor color)
539 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000540 }
djsollen@google.com08337772012-06-26 14:33:13 +0000541
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000542 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
543 return fDirection;
544 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000545 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000546 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000547 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000548 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
549#if SK_SUPPORT_GPU
550 return SkNEW(GrGLDistantLight);
551#else
552 SkDEBUGFAIL("Should not call in GPU-less build");
553 return NULL;
554#endif
555 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000556 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
557 if (other.type() != kDistant_LightType) {
558 return false;
559 }
560
561 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
562 return INHERITED::isEqual(other) &&
563 fDirection == o.fDirection;
564 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000565
566 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
567
djsollen@google.com08337772012-06-26 14:33:13 +0000568protected:
569 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
570 fDirection = readPoint3(buffer);
571 }
572 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
573 INHERITED::flatten(buffer);
574 writePoint3(fDirection, buffer);
575 }
576
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000577private:
djsollen@google.com08337772012-06-26 14:33:13 +0000578 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000579 SkPoint3 fDirection;
580};
581
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000582///////////////////////////////////////////////////////////////////////////////
583
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000584class SkPointLight : public SkLight {
585public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000586 SkPointLight(const SkPoint3& location, SkColor color)
587 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000588
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
590 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
591 fLocation.fY - SkIntToScalar(y),
592 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
593 direction.normalize();
594 return direction;
595 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000596 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000597 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000598 const SkPoint3& location() const { return fLocation; }
599 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000600#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000601 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000602#else
603 SkDEBUGFAIL("Should not call in GPU-less build");
604 return NULL;
605#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000606 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000607 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000608 if (other.type() != kPoint_LightType) {
609 return false;
610 }
611 const SkPointLight& o = static_cast<const SkPointLight&>(other);
612 return INHERITED::isEqual(other) &&
613 fLocation == o.fLocation;
614 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000615
616 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
617
djsollen@google.com08337772012-06-26 14:33:13 +0000618protected:
619 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
620 fLocation = readPoint3(buffer);
621 }
622 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
623 INHERITED::flatten(buffer);
624 writePoint3(fLocation, buffer);
625 }
626
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000627private:
djsollen@google.com08337772012-06-26 14:33:13 +0000628 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000629 SkPoint3 fLocation;
630};
631
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632///////////////////////////////////////////////////////////////////////////////
633
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000634class SkSpotLight : public SkLight {
635public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000636 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
637 : INHERITED(color),
638 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000639 fTarget(target),
640 fSpecularExponent(specularExponent)
641 {
642 fS = target - location;
643 fS.normalize();
644 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
645 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
646 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
647 fConeScale = SkScalarInvert(antiAliasThreshold);
648 }
djsollen@google.com08337772012-06-26 14:33:13 +0000649
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000650 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
651 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
652 fLocation.fY - SkIntToScalar(y),
653 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
654 direction.normalize();
655 return direction;
656 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000657 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000658 SkScalar cosAngle = -surfaceToLight.dot(fS);
659 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000660 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000661 }
662 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
663 if (cosAngle < fCosInnerConeAngle) {
664 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000665 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000666 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000667 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000668 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000669 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000670#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000671 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000672#else
673 SkDEBUGFAIL("Should not call in GPU-less build");
674 return NULL;
675#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000676 }
djsollen@google.com08337772012-06-26 14:33:13 +0000677 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000678 const SkPoint3& location() const { return fLocation; }
679 const SkPoint3& target() const { return fTarget; }
680 SkScalar specularExponent() const { return fSpecularExponent; }
681 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
682 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
683 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000684 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000685
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000686 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
687
djsollen@google.com08337772012-06-26 14:33:13 +0000688protected:
689 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
690 fLocation = readPoint3(buffer);
691 fTarget = readPoint3(buffer);
692 fSpecularExponent = buffer.readScalar();
693 fCosOuterConeAngle = buffer.readScalar();
694 fCosInnerConeAngle = buffer.readScalar();
695 fConeScale = buffer.readScalar();
696 fS = readPoint3(buffer);
697 }
698 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
699 INHERITED::flatten(buffer);
700 writePoint3(fLocation, buffer);
701 writePoint3(fTarget, buffer);
702 buffer.writeScalar(fSpecularExponent);
703 buffer.writeScalar(fCosOuterConeAngle);
704 buffer.writeScalar(fCosInnerConeAngle);
705 buffer.writeScalar(fConeScale);
706 writePoint3(fS, buffer);
707 }
708
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000709 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000710 if (other.type() != kSpot_LightType) {
711 return false;
712 }
713
714 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
715 return INHERITED::isEqual(other) &&
716 fLocation == o.fLocation &&
717 fTarget == o.fTarget &&
718 fSpecularExponent == o.fSpecularExponent &&
719 fCosOuterConeAngle == o.fCosOuterConeAngle;
720 }
721
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000722private:
djsollen@google.com08337772012-06-26 14:33:13 +0000723 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000724 SkPoint3 fLocation;
725 SkPoint3 fTarget;
726 SkScalar fSpecularExponent;
727 SkScalar fCosOuterConeAngle;
728 SkScalar fCosInnerConeAngle;
729 SkScalar fConeScale;
730 SkPoint3 fS;
731};
732
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000733///////////////////////////////////////////////////////////////////////////////
734
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000735SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input)
736 : INHERITED(input),
737 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
739{
740 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000741 // our caller knows that we take ownership of the light, so we don't
742 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743}
744
745SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000746 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000747 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000748 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000749 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
750 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000751}
752
753SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000754 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000755 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000756 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000757 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
758 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000759}
760
761SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000762 const SkPoint3& location, const SkPoint3& target,
763 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000764 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
765 SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000766 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000767 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
768 cutoffAngle, lightColor)),
769 surfaceScale, kd, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000770}
771
772SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000773 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000774 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000775 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000776 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
777 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000778}
779
780SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000781 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000782 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000783 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000784 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
785 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786}
787
788SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000789 const SkPoint3& location, const SkPoint3& target,
790 SkScalar specularExponent, SkScalar cutoffAngle,
791 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000792 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000793 return SkNEW_ARGS(SkSpecularLightingImageFilter,
794 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000795 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000796}
797
798SkLightingImageFilter::~SkLightingImageFilter() {
799 fLight->unref();
800}
801
802SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
803 : INHERITED(buffer)
804{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000805 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000806 fSurfaceScale = buffer.readScalar();
807}
808
809void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
810 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000811 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000812 buffer.writeScalar(fSurfaceScale);
813}
814
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000815///////////////////////////////////////////////////////////////////////////////
816
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000817SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input)
818 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000819 fKD(kd)
820{
821}
822
823SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
824 : INHERITED(buffer)
825{
826 fKD = buffer.readScalar();
827}
828
829void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
830 this->INHERITED::flatten(buffer);
831 buffer.writeScalar(fKD);
832}
833
834bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
835 const SkBitmap& src,
836 const SkMatrix&,
837 SkBitmap* dst,
838 SkIPoint*) {
839 if (src.config() != SkBitmap::kARGB_8888_Config) {
840 return false;
841 }
842 SkAutoLockPixels alp(src);
843 if (!src.getPixels()) {
844 return false;
845 }
846 if (src.width() < 2 || src.height() < 2) {
847 return false;
848 }
849 dst->setConfig(src.config(), src.width(), src.height());
850 dst->allocPixels();
851
852 DiffuseLightingType lightingType(fKD);
853 switch (light()->type()) {
854 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000855 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000856 break;
857 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000858 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000859 break;
860 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000861 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000862 break;
863 }
864 return true;
865}
866
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000867#if SK_SUPPORT_GPU
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000868bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000869 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000870 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000871 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000872 }
873 return true;
874}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000875#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000876
877///////////////////////////////////////////////////////////////////////////////
878
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000879SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input)
880 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000881 fKS(ks),
882 fShininess(shininess)
883{
884}
885
886SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
887 : INHERITED(buffer)
888{
889 fKS = buffer.readScalar();
890 fShininess = buffer.readScalar();
891}
892
893void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
894 this->INHERITED::flatten(buffer);
895 buffer.writeScalar(fKS);
896 buffer.writeScalar(fShininess);
897}
898
899bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
900 const SkBitmap& src,
901 const SkMatrix&,
902 SkBitmap* dst,
903 SkIPoint*) {
904 if (src.config() != SkBitmap::kARGB_8888_Config) {
905 return false;
906 }
907 SkAutoLockPixels alp(src);
908 if (!src.getPixels()) {
909 return false;
910 }
911 if (src.width() < 2 || src.height() < 2) {
912 return false;
913 }
914 dst->setConfig(src.config(), src.width(), src.height());
915 dst->allocPixels();
916
917 SpecularLightingType lightingType(fKS, fShininess);
918 switch (light()->type()) {
919 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000920 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000921 break;
922 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000923 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000924 break;
925 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000926 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000927 break;
928 }
929 return true;
930}
931
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000932#if SK_SUPPORT_GPU
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000933bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
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;
939}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000940#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000941
942///////////////////////////////////////////////////////////////////////////////
943
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000944#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000945
946namespace {
bsalomon@google.com73a96942013-02-13 16:31:19 +0000947SkPoint3 random_point3(SkMWCRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000948 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
949 SkScalarToFloat(random->nextSScalar1()),
950 SkScalarToFloat(random->nextSScalar1()));
951}
952
bsalomon@google.com73a96942013-02-13 16:31:19 +0000953SkLight* create_random_light(SkMWCRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000954 int type = random->nextULessThan(3);
955 switch (type) {
956 case 0: {
957 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
958 }
959 case 1: {
960 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
961 }
962 case 2: {
963 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
964 random_point3(random),
965 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000966 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000967 random->nextU()));
968 }
969 default:
970 GrCrash();
971 return NULL;
972 }
973}
974
975}
976
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000977class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000978public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000979 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000980 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000981 virtual ~GrGLLightingEffect();
982
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000983 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000984 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000985 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000986 const char* outputColor,
987 const char* inputColor,
988 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000989
bsalomon@google.comc7818882013-03-20 19:19:53 +0000990 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000991
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000992 /**
993 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
994 */
bsalomon@google.comc7818882013-03-20 19:19:53 +0000995 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000996
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000997protected:
998 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
999
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001001 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001002
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001003 UniformHandle fImageIncrementUni;
1004 UniformHandle fSurfaceScaleUni;
1005 GrGLLight* fLight;
1006 GrGLEffectMatrix fEffectMatrix;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001007};
1008
1009///////////////////////////////////////////////////////////////////////////////
1010
1011class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1012public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001013 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001014 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001015 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001016 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001017
1018private:
1019 typedef GrGLLightingEffect INHERITED;
1020
bsalomon@google.com032b2212012-07-16 13:36:18 +00001021 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001022};
1023
1024///////////////////////////////////////////////////////////////////////////////
1025
1026class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1027public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001028 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001029 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001030 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001031 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001032
1033private:
1034 typedef GrGLLightingEffect INHERITED;
1035
bsalomon@google.com032b2212012-07-16 13:36:18 +00001036 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001037 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001038};
1039
1040///////////////////////////////////////////////////////////////////////////////
1041
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001042GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001043 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001044 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001045 , fSurfaceScale(surfaceScale) {
1046 fLight->ref();
1047}
1048
1049GrLightingEffect::~GrLightingEffect() {
1050 fLight->unref();
1051}
1052
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001053bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001054 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001055 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001056 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001057 fSurfaceScale == s.fSurfaceScale;
1058}
1059
1060///////////////////////////////////////////////////////////////////////////////
1061
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001062GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1063 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001064}
1065
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001066const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1067 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001068}
1069
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001070bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001071 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001072 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001073 this->kd() == s.kd();
1074}
1075
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001076GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001077
bsalomon@google.com73a96942013-02-13 16:31:19 +00001078GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkMWCRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001079 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001080 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001081 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001082 SkScalar surfaceScale = random->nextSScalar1();
1083 SkScalar kd = random->nextUScalar1();
1084 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001085 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1086 light, surfaceScale, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001087}
1088
1089
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001090///////////////////////////////////////////////////////////////////////////////
1091
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001092GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001093 const GrDrawEffect& drawEffect)
bsalomon@google.com374e7592012-10-23 17:30:45 +00001094 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001095 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comc7818882013-03-20 19:19:53 +00001096 , fSurfaceScaleUni(kInvalidUniformHandle)
1097 , fEffectMatrix(drawEffect.castEffect<GrLightingEffect>().coordsType()) {
1098 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001099 fLight = m.light()->createGLLight();
1100}
1101
1102GrGLLightingEffect::~GrGLLightingEffect() {
1103 delete fLight;
1104}
1105
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001106void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001107 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001108 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001109 const char* outputColor,
1110 const char* inputColor,
1111 const TextureSamplerArray& samplers) {
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001112 const char* coords;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001113 fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001114
bsalomon@google.com032b2212012-07-16 13:36:18 +00001115 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1116 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001117 "ImageIncrement");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001118 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1119 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001120 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001121 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001122 SkString lightFunc;
1123 this->emitLightFunc(builder, &lightFunc);
1124 static const GrGLShaderVar gSobelArgs[] = {
1125 GrGLShaderVar("a", kFloat_GrSLType),
1126 GrGLShaderVar("b", kFloat_GrSLType),
1127 GrGLShaderVar("c", kFloat_GrSLType),
1128 GrGLShaderVar("d", kFloat_GrSLType),
1129 GrGLShaderVar("e", kFloat_GrSLType),
1130 GrGLShaderVar("f", kFloat_GrSLType),
1131 GrGLShaderVar("scale", kFloat_GrSLType),
1132 };
1133 SkString sobelFuncName;
1134 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1135 kFloat_GrSLType,
1136 "sobel",
1137 SK_ARRAY_COUNT(gSobelArgs),
1138 gSobelArgs,
1139 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1140 &sobelFuncName);
1141 static const GrGLShaderVar gPointToNormalArgs[] = {
1142 GrGLShaderVar("x", kFloat_GrSLType),
1143 GrGLShaderVar("y", kFloat_GrSLType),
1144 GrGLShaderVar("scale", kFloat_GrSLType),
1145 };
1146 SkString pointToNormalName;
1147 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1148 kVec3f_GrSLType,
1149 "pointToNormal",
1150 SK_ARRAY_COUNT(gPointToNormalArgs),
1151 gPointToNormalArgs,
bsalomon@google.com706f6682012-10-23 14:53:55 +00001152 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001153 &pointToNormalName);
1154
1155 static const GrGLShaderVar gInteriorNormalArgs[] = {
1156 GrGLShaderVar("m", kFloat_GrSLType, 9),
1157 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1158 };
1159 SkString interiorNormalBody;
1160 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1161 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1162 "\t surfaceScale);\n",
1163 pointToNormalName.c_str(),
1164 sobelFuncName.c_str(),
1165 sobelFuncName.c_str());
1166 SkString interiorNormalName;
1167 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1168 kVec3f_GrSLType,
1169 "interiorNormal",
1170 SK_ARRAY_COUNT(gInteriorNormalArgs),
1171 gInteriorNormalArgs,
1172 interiorNormalBody.c_str(),
1173 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001174
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001175 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords);
1176 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001177
1178 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1179 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1180
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001181 int index = 0;
1182 for (int dy = -1; dy <= 1; dy++) {
1183 for (int dx = -1; dx <= 1; dx++) {
1184 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001185 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001186 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
1187 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
1188 samplers[0],
1189 texCoords.c_str());
1190 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001191 }
1192 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001193 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001195 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001196 fLight->emitSurfaceToLight(builder, arg.c_str());
1197 builder->fsCodeAppend(";\n");
1198 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1199 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001200 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001201 builder->fsCodeAppend(");\n");
1202 SkString modulate;
1203 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1204 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001205}
1206
bsalomon@google.comc7818882013-03-20 19:19:53 +00001207GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001208 const GrGLCaps& caps) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001209 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1210 EffectKey key = lighting.light()->type();
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001211 key <<= GrGLEffectMatrix::kKeyBits;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001212 EffectKey matrixKey = GrGLEffectMatrix::GenKey(lighting.getMatrix(),
1213 drawEffect,
1214 lighting.coordsType(),
1215 lighting.texture(0));
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001216 return key | matrixKey;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001217}
1218
bsalomon@google.comc7818882013-03-20 19:19:53 +00001219void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1220 const GrDrawEffect& drawEffect) {
1221 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1222 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001223 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001224 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001225 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
1226 fLight->setData(uman, lighting.light());
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001227 fEffectMatrix.setData(uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001228 lighting.getMatrix(),
1229 drawEffect,
1230 lighting.texture(0));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001231}
1232
1233///////////////////////////////////////////////////////////////////////////////
1234
1235///////////////////////////////////////////////////////////////////////////////
1236
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001237GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001238 const GrDrawEffect& drawEffect)
1239 : INHERITED(factory, drawEffect)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001240 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001241}
1242
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001243void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001244 const char* kd;
1245 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1246 kFloat_GrSLType,
1247 "KD",
1248 &kd);
1249
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001250 static const GrGLShaderVar gLightArgs[] = {
1251 GrGLShaderVar("normal", kVec3f_GrSLType),
1252 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1253 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1254 };
1255 SkString lightBody;
1256 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1257 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1258 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1259 kVec4f_GrSLType,
1260 "light",
1261 SK_ARRAY_COUNT(gLightArgs),
1262 gLightArgs,
1263 lightBody.c_str(),
1264 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001265}
1266
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001267void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001268 const GrDrawEffect& drawEffect) {
1269 INHERITED::setData(uman, drawEffect);
1270 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1271 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001272}
1273
1274///////////////////////////////////////////////////////////////////////////////
1275
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001276GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1277 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001278 fKS(ks),
1279 fShininess(shininess) {
1280}
1281
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001282const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1283 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001284}
1285
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001286bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001287 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001288 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001289 this->ks() == s.ks() &&
1290 this->shininess() == s.shininess();
1291}
1292
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001293GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001294
bsalomon@google.com73a96942013-02-13 16:31:19 +00001295GrEffectRef* GrSpecularLightingEffect::TestCreate(SkMWCRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001296 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001297 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001298 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.comc7818882013-03-20 19:19:53 +00001310 const GrDrawEffect& drawEffect)
1311 : GrGLLightingEffect(factory, drawEffect)
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.comc7818882013-03-20 19:19:53 +00001345 const GrDrawEffect& drawEffect) {
1346 INHERITED::setData(uman, drawEffect);
1347 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1348 uman.set1f(fKSUni, spec.ks());
1349 uman.set1f(fShininessUni, spec.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.comc7818882013-03-20 19:19:53 +00001363void GrGLLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001364 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001365}
1366
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001367///////////////////////////////////////////////////////////////////////////////
1368
bsalomon@google.com706f6682012-10-23 14:53:55 +00001369void GrGLDistantLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
1370 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001371 SkASSERT(light->type() == SkLight::kDistant_LightType);
1372 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001373 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001374}
1375
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001376void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001377 const char* dir;
1378 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1379 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001380 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001381}
1382
1383///////////////////////////////////////////////////////////////////////////////
1384
bsalomon@google.comc7818882013-03-20 19:19:53 +00001385void GrGLPointLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001386 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001387 SkASSERT(light->type() == SkLight::kPoint_LightType);
1388 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001389 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001390}
1391
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001392void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001393 const char* loc;
1394 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1395 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001396 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001397}
1398
1399///////////////////////////////////////////////////////////////////////////////
1400
bsalomon@google.comc7818882013-03-20 19:19:53 +00001401void GrGLSpotLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001402 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001403 SkASSERT(light->type() == SkLight::kSpot_LightType);
1404 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001405 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001406 uman.set1f(fExponentUni, spotLight->specularExponent());
1407 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1408 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1409 uman.set1f(fConeScaleUni, spotLight->coneScale());
1410 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001411}
1412
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001413void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001414 const char* location;
1415 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1416 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001417 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1418 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001419}
1420
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001421void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1422 const char *surfaceToLight) {
1423
1424 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1425
1426 const char* exponent;
1427 const char* cosInner;
1428 const char* cosOuter;
1429 const char* coneScale;
1430 const char* s;
1431 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1432 kFloat_GrSLType, "Exponent", &exponent);
1433 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1434 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1435 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1436 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1437 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1438 kFloat_GrSLType, "ConeScale", &coneScale);
1439 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1440 kVec3f_GrSLType, "S", &s);
1441
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001442 static const GrGLShaderVar gLightColorArgs[] = {
1443 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1444 };
1445 SkString lightColorBody;
1446 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1447 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1448 lightColorBody.appendf("\t\treturn vec3(0);\n");
1449 lightColorBody.appendf("\t}\n");
1450 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1451 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1452 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1453 color, cosOuter, coneScale);
1454 lightColorBody.appendf("\t}\n");
1455 lightColorBody.appendf("\treturn %s;\n", color);
1456 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1457 kVec3f_GrSLType,
1458 "lightColor",
1459 SK_ARRAY_COUNT(gLightColorArgs),
1460 gLightColorArgs,
1461 lightColorBody.c_str(),
1462 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001463
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001464 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001465}
1466
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001467#endif
1468
djsollen@google.com08337772012-06-26 14:33:13 +00001469SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1470 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1471 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1472 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1473 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1474 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1475SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END