blob: c86bf6b628c59917df0424286022670c79d45ac2 [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;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000450
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000451private:
452 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000453 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000454};
455
456///////////////////////////////////////////////////////////////////////////////
457
458class GrGLPointLight : public GrGLLight {
459public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000460 virtual ~GrGLPointLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000461 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000462 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000463
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000464private:
465 typedef GrGLLight INHERITED;
466 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000467 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000468};
469
470///////////////////////////////////////////////////////////////////////////////
471
472class GrGLSpotLight : public GrGLLight {
473public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000474 virtual ~GrGLSpotLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000475 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000476 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000477 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000478
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000479private:
480 typedef GrGLLight INHERITED;
481
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000482 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000483 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000484 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000485 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000486 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000487 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000488 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000489};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000490#else
491
492class GrGLLight;
493
494#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000495
496};
497
498///////////////////////////////////////////////////////////////////////////////
499
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000500class SkLight : public SkFlattenable {
501public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000502 SK_DECLARE_INST_COUNT(SkLight)
503
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000504 enum LightType {
505 kDistant_LightType,
506 kPoint_LightType,
507 kSpot_LightType,
508 };
509 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000510 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000511 virtual GrGLLight* createGLLight() const = 0;
512 virtual bool isEqual(const SkLight& other) const {
513 return fColor == other.fColor;
514 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000515 // Called to know whether the generated GrGLLight will require access to the fragment position.
516 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000517
djsollen@google.com08337772012-06-26 14:33:13 +0000518protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000519 SkLight(SkColor color)
520 : fColor(SkIntToScalar(SkColorGetR(color)),
521 SkIntToScalar(SkColorGetG(color)),
522 SkIntToScalar(SkColorGetB(color))) {}
523 SkLight(SkFlattenableReadBuffer& buffer)
524 : INHERITED(buffer) {
525 fColor = readPoint3(buffer);
526 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000527 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000528 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000529 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000530 }
djsollen@google.com08337772012-06-26 14:33:13 +0000531
532private:
533 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000534 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000535};
536
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000537SK_DEFINE_INST_COUNT(SkLight)
538
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000539///////////////////////////////////////////////////////////////////////////////
540
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000541class SkDistantLight : public SkLight {
542public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000543 SkDistantLight(const SkPoint3& direction, SkColor color)
544 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000545 }
djsollen@google.com08337772012-06-26 14:33:13 +0000546
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000547 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
548 return fDirection;
549 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000550 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000551 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000552 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000553 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
554#if SK_SUPPORT_GPU
555 return SkNEW(GrGLDistantLight);
556#else
557 SkDEBUGFAIL("Should not call in GPU-less build");
558 return NULL;
559#endif
560 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000561 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
562
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000563 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
564 if (other.type() != kDistant_LightType) {
565 return false;
566 }
567
568 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
569 return INHERITED::isEqual(other) &&
570 fDirection == o.fDirection;
571 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000572
573 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
574
djsollen@google.com08337772012-06-26 14:33:13 +0000575protected:
576 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
577 fDirection = readPoint3(buffer);
578 }
579 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
580 INHERITED::flatten(buffer);
581 writePoint3(fDirection, buffer);
582 }
583
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000584private:
djsollen@google.com08337772012-06-26 14:33:13 +0000585 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586 SkPoint3 fDirection;
587};
588
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000589///////////////////////////////////////////////////////////////////////////////
590
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591class SkPointLight : public SkLight {
592public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000593 SkPointLight(const SkPoint3& location, SkColor color)
594 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000595
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000596 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
597 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
598 fLocation.fY - SkIntToScalar(y),
599 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
600 direction.normalize();
601 return direction;
602 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000603 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000604 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000605 const SkPoint3& location() const { return fLocation; }
606 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000607#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000608 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000609#else
610 SkDEBUGFAIL("Should not call in GPU-less build");
611 return NULL;
612#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000613 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000614 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000615 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000616 if (other.type() != kPoint_LightType) {
617 return false;
618 }
619 const SkPointLight& o = static_cast<const SkPointLight&>(other);
620 return INHERITED::isEqual(other) &&
621 fLocation == o.fLocation;
622 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000623
624 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
625
djsollen@google.com08337772012-06-26 14:33:13 +0000626protected:
627 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
628 fLocation = readPoint3(buffer);
629 }
630 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
631 INHERITED::flatten(buffer);
632 writePoint3(fLocation, buffer);
633 }
634
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000635private:
djsollen@google.com08337772012-06-26 14:33:13 +0000636 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000637 SkPoint3 fLocation;
638};
639
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000640///////////////////////////////////////////////////////////////////////////////
641
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000642class SkSpotLight : public SkLight {
643public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000644 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
645 : INHERITED(color),
646 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000647 fTarget(target),
648 fSpecularExponent(specularExponent)
649 {
650 fS = target - location;
651 fS.normalize();
652 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
653 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
654 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
655 fConeScale = SkScalarInvert(antiAliasThreshold);
656 }
djsollen@google.com08337772012-06-26 14:33:13 +0000657
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000658 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
659 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
660 fLocation.fY - SkIntToScalar(y),
661 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
662 direction.normalize();
663 return direction;
664 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000665 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000666 SkScalar cosAngle = -surfaceToLight.dot(fS);
667 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000668 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000669 }
670 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
671 if (cosAngle < fCosInnerConeAngle) {
672 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000673 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000674 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000675 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000676 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000677 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000678#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000679 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000680#else
681 SkDEBUGFAIL("Should not call in GPU-less build");
682 return NULL;
683#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000684 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000685 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000686 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000687 const SkPoint3& location() const { return fLocation; }
688 const SkPoint3& target() const { return fTarget; }
689 SkScalar specularExponent() const { return fSpecularExponent; }
690 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
691 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
692 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000693 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000694
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
696
djsollen@google.com08337772012-06-26 14:33:13 +0000697protected:
698 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
699 fLocation = readPoint3(buffer);
700 fTarget = readPoint3(buffer);
701 fSpecularExponent = buffer.readScalar();
702 fCosOuterConeAngle = buffer.readScalar();
703 fCosInnerConeAngle = buffer.readScalar();
704 fConeScale = buffer.readScalar();
705 fS = readPoint3(buffer);
706 }
707 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
708 INHERITED::flatten(buffer);
709 writePoint3(fLocation, buffer);
710 writePoint3(fTarget, buffer);
711 buffer.writeScalar(fSpecularExponent);
712 buffer.writeScalar(fCosOuterConeAngle);
713 buffer.writeScalar(fCosInnerConeAngle);
714 buffer.writeScalar(fConeScale);
715 writePoint3(fS, buffer);
716 }
717
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000718 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000719 if (other.type() != kSpot_LightType) {
720 return false;
721 }
722
723 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
724 return INHERITED::isEqual(other) &&
725 fLocation == o.fLocation &&
726 fTarget == o.fTarget &&
727 fSpecularExponent == o.fSpecularExponent &&
728 fCosOuterConeAngle == o.fCosOuterConeAngle;
729 }
730
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731private:
djsollen@google.com08337772012-06-26 14:33:13 +0000732 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733 SkPoint3 fLocation;
734 SkPoint3 fTarget;
735 SkScalar fSpecularExponent;
736 SkScalar fCosOuterConeAngle;
737 SkScalar fCosInnerConeAngle;
738 SkScalar fConeScale;
739 SkPoint3 fS;
740};
741
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000742///////////////////////////////////////////////////////////////////////////////
743
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000744SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input)
745 : INHERITED(input),
746 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000747 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
748{
749 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000750 // our caller knows that we take ownership of the light, so we don't
751 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000752}
753
754SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000755 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000756 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000757 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000758 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
759 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000760}
761
762SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000763 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000764 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000765 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000766 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
767 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000768}
769
770SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000771 const SkPoint3& location, const SkPoint3& target,
772 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000773 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
774 SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000775 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000776 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
777 cutoffAngle, lightColor)),
778 surfaceScale, kd, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779}
780
781SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000782 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000783 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000784 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000785 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
786 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000787}
788
789SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000790 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000791 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000792 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000793 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
794 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000795}
796
797SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000798 const SkPoint3& location, const SkPoint3& target,
799 SkScalar specularExponent, SkScalar cutoffAngle,
800 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000801 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000802 return SkNEW_ARGS(SkSpecularLightingImageFilter,
803 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000804 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000805}
806
807SkLightingImageFilter::~SkLightingImageFilter() {
808 fLight->unref();
809}
810
811SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
812 : INHERITED(buffer)
813{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000814 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000815 fSurfaceScale = buffer.readScalar();
816}
817
818void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
819 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000820 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000821 buffer.writeScalar(fSurfaceScale);
822}
823
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000824///////////////////////////////////////////////////////////////////////////////
825
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000826SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input)
827 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000828 fKD(kd)
829{
830}
831
832SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
833 : INHERITED(buffer)
834{
835 fKD = buffer.readScalar();
836}
837
838void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
839 this->INHERITED::flatten(buffer);
840 buffer.writeScalar(fKD);
841}
842
843bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
844 const SkBitmap& src,
845 const SkMatrix&,
846 SkBitmap* dst,
847 SkIPoint*) {
848 if (src.config() != SkBitmap::kARGB_8888_Config) {
849 return false;
850 }
851 SkAutoLockPixels alp(src);
852 if (!src.getPixels()) {
853 return false;
854 }
855 if (src.width() < 2 || src.height() < 2) {
856 return false;
857 }
858 dst->setConfig(src.config(), src.width(), src.height());
859 dst->allocPixels();
860
861 DiffuseLightingType lightingType(fKD);
862 switch (light()->type()) {
863 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000864 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000865 break;
866 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000867 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000868 break;
869 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000870 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000871 break;
872 }
873 return true;
874}
875
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000876#if SK_SUPPORT_GPU
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000877bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000878 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000879 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000880 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000881 }
882 return true;
883}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000884#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000885
886///////////////////////////////////////////////////////////////////////////////
887
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000888SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input)
889 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000890 fKS(ks),
891 fShininess(shininess)
892{
893}
894
895SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
896 : INHERITED(buffer)
897{
898 fKS = buffer.readScalar();
899 fShininess = buffer.readScalar();
900}
901
902void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
903 this->INHERITED::flatten(buffer);
904 buffer.writeScalar(fKS);
905 buffer.writeScalar(fShininess);
906}
907
908bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
909 const SkBitmap& src,
910 const SkMatrix&,
911 SkBitmap* dst,
912 SkIPoint*) {
913 if (src.config() != SkBitmap::kARGB_8888_Config) {
914 return false;
915 }
916 SkAutoLockPixels alp(src);
917 if (!src.getPixels()) {
918 return false;
919 }
920 if (src.width() < 2 || src.height() < 2) {
921 return false;
922 }
923 dst->setConfig(src.config(), src.width(), src.height());
924 dst->allocPixels();
925
926 SpecularLightingType lightingType(fKS, fShininess);
927 switch (light()->type()) {
928 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000929 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000930 break;
931 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000932 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000933 break;
934 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000935 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000936 break;
937 }
938 return true;
939}
940
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000941#if SK_SUPPORT_GPU
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000942bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000943 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000944 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000945 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000946 }
947 return true;
948}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000949#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000950
951///////////////////////////////////////////////////////////////////////////////
952
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000953#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000954
955namespace {
bsalomon@google.com73a96942013-02-13 16:31:19 +0000956SkPoint3 random_point3(SkMWCRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000957 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
958 SkScalarToFloat(random->nextSScalar1()),
959 SkScalarToFloat(random->nextSScalar1()));
960}
961
bsalomon@google.com73a96942013-02-13 16:31:19 +0000962SkLight* create_random_light(SkMWCRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000963 int type = random->nextULessThan(3);
964 switch (type) {
965 case 0: {
966 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
967 }
968 case 1: {
969 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
970 }
971 case 2: {
972 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
973 random_point3(random),
974 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000975 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000976 random->nextU()));
977 }
978 default:
979 GrCrash();
980 return NULL;
981 }
982}
983
984}
985
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000986class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000987public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000988 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000989 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000990 virtual ~GrGLLightingEffect();
991
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000992 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000993 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000994 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000995 const char* outputColor,
996 const char* inputColor,
997 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000998
bsalomon@google.comc7818882013-03-20 19:19:53 +0000999 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001001 /**
1002 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1003 */
bsalomon@google.comc7818882013-03-20 19:19:53 +00001004 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001005
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001006protected:
1007 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1008
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001009private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001010 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001011
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001012 UniformHandle fImageIncrementUni;
1013 UniformHandle fSurfaceScaleUni;
1014 GrGLLight* fLight;
1015 GrGLEffectMatrix fEffectMatrix;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001016};
1017
1018///////////////////////////////////////////////////////////////////////////////
1019
1020class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1021public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001022 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001023 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001024 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001025 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001026
1027private:
1028 typedef GrGLLightingEffect INHERITED;
1029
bsalomon@google.com032b2212012-07-16 13:36:18 +00001030 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001031};
1032
1033///////////////////////////////////////////////////////////////////////////////
1034
1035class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1036public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001037 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001038 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001039 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001040 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001041
1042private:
1043 typedef GrGLLightingEffect INHERITED;
1044
bsalomon@google.com032b2212012-07-16 13:36:18 +00001045 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001046 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001047};
1048
1049///////////////////////////////////////////////////////////////////////////////
1050
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001051GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001052 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001053 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001054 , fSurfaceScale(surfaceScale) {
1055 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001056 if (light->requiresFragmentPosition()) {
1057 this->setWillReadFragmentPosition();
1058 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001059}
1060
1061GrLightingEffect::~GrLightingEffect() {
1062 fLight->unref();
1063}
1064
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001065bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001066 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001067 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001068 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001069 fSurfaceScale == s.fSurfaceScale;
1070}
1071
1072///////////////////////////////////////////////////////////////////////////////
1073
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001074GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1075 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001076}
1077
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001078const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1079 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001080}
1081
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001082bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001083 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001084 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001085 this->kd() == s.kd();
1086}
1087
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001088GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001089
bsalomon@google.com73a96942013-02-13 16:31:19 +00001090GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkMWCRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001091 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001092 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001093 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001094 SkScalar surfaceScale = random->nextSScalar1();
1095 SkScalar kd = random->nextUScalar1();
1096 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001097 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1098 light, surfaceScale, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001099}
1100
1101
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001102///////////////////////////////////////////////////////////////////////////////
1103
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001104GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001105 const GrDrawEffect& drawEffect)
bsalomon@google.com374e7592012-10-23 17:30:45 +00001106 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001107 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comc7818882013-03-20 19:19:53 +00001108 , fSurfaceScaleUni(kInvalidUniformHandle)
1109 , fEffectMatrix(drawEffect.castEffect<GrLightingEffect>().coordsType()) {
1110 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001111 fLight = m.light()->createGLLight();
1112}
1113
1114GrGLLightingEffect::~GrGLLightingEffect() {
1115 delete fLight;
1116}
1117
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001118void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001119 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001120 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001121 const char* outputColor,
1122 const char* inputColor,
1123 const TextureSamplerArray& samplers) {
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001124 const char* coords;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001125 fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001126
bsalomon@google.com032b2212012-07-16 13:36:18 +00001127 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1128 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001129 "ImageIncrement");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001130 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1131 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001132 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001133 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001134 SkString lightFunc;
1135 this->emitLightFunc(builder, &lightFunc);
1136 static const GrGLShaderVar gSobelArgs[] = {
1137 GrGLShaderVar("a", kFloat_GrSLType),
1138 GrGLShaderVar("b", kFloat_GrSLType),
1139 GrGLShaderVar("c", kFloat_GrSLType),
1140 GrGLShaderVar("d", kFloat_GrSLType),
1141 GrGLShaderVar("e", kFloat_GrSLType),
1142 GrGLShaderVar("f", kFloat_GrSLType),
1143 GrGLShaderVar("scale", kFloat_GrSLType),
1144 };
1145 SkString sobelFuncName;
1146 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1147 kFloat_GrSLType,
1148 "sobel",
1149 SK_ARRAY_COUNT(gSobelArgs),
1150 gSobelArgs,
1151 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1152 &sobelFuncName);
1153 static const GrGLShaderVar gPointToNormalArgs[] = {
1154 GrGLShaderVar("x", kFloat_GrSLType),
1155 GrGLShaderVar("y", kFloat_GrSLType),
1156 GrGLShaderVar("scale", kFloat_GrSLType),
1157 };
1158 SkString pointToNormalName;
1159 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1160 kVec3f_GrSLType,
1161 "pointToNormal",
1162 SK_ARRAY_COUNT(gPointToNormalArgs),
1163 gPointToNormalArgs,
bsalomon@google.com706f6682012-10-23 14:53:55 +00001164 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001165 &pointToNormalName);
1166
1167 static const GrGLShaderVar gInteriorNormalArgs[] = {
1168 GrGLShaderVar("m", kFloat_GrSLType, 9),
1169 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1170 };
1171 SkString interiorNormalBody;
1172 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1173 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1174 "\t surfaceScale);\n",
1175 pointToNormalName.c_str(),
1176 sobelFuncName.c_str(),
1177 sobelFuncName.c_str());
1178 SkString interiorNormalName;
1179 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1180 kVec3f_GrSLType,
1181 "interiorNormal",
1182 SK_ARRAY_COUNT(gInteriorNormalArgs),
1183 gInteriorNormalArgs,
1184 interiorNormalBody.c_str(),
1185 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001186
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001187 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords);
1188 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001189
1190 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1191 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1192
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001193 int index = 0;
1194 for (int dy = -1; dy <= 1; dy++) {
1195 for (int dx = -1; dx <= 1; dx++) {
1196 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001197 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001198 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
1199 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
1200 samplers[0],
1201 texCoords.c_str());
1202 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001203 }
1204 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001205 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001206 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001207 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001208 fLight->emitSurfaceToLight(builder, arg.c_str());
1209 builder->fsCodeAppend(";\n");
1210 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1211 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001212 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001213 builder->fsCodeAppend(");\n");
1214 SkString modulate;
1215 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1216 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001217}
1218
bsalomon@google.comc7818882013-03-20 19:19:53 +00001219GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001220 const GrGLCaps& caps) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001221 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1222 EffectKey key = lighting.light()->type();
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001223 key <<= GrGLEffectMatrix::kKeyBits;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001224 EffectKey matrixKey = GrGLEffectMatrix::GenKey(lighting.getMatrix(),
1225 drawEffect,
1226 lighting.coordsType(),
1227 lighting.texture(0));
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001228 return key | matrixKey;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229}
1230
bsalomon@google.comc7818882013-03-20 19:19:53 +00001231void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1232 const GrDrawEffect& drawEffect) {
1233 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1234 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001235 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001236 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001237 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
1238 fLight->setData(uman, lighting.light());
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001239 fEffectMatrix.setData(uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001240 lighting.getMatrix(),
1241 drawEffect,
1242 lighting.texture(0));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001243}
1244
1245///////////////////////////////////////////////////////////////////////////////
1246
1247///////////////////////////////////////////////////////////////////////////////
1248
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001249GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001250 const GrDrawEffect& drawEffect)
1251 : INHERITED(factory, drawEffect)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001252 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001253}
1254
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001255void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001256 const char* kd;
1257 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1258 kFloat_GrSLType,
1259 "KD",
1260 &kd);
1261
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001262 static const GrGLShaderVar gLightArgs[] = {
1263 GrGLShaderVar("normal", kVec3f_GrSLType),
1264 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1265 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1266 };
1267 SkString lightBody;
1268 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1269 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1270 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1271 kVec4f_GrSLType,
1272 "light",
1273 SK_ARRAY_COUNT(gLightArgs),
1274 gLightArgs,
1275 lightBody.c_str(),
1276 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001277}
1278
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001279void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001280 const GrDrawEffect& drawEffect) {
1281 INHERITED::setData(uman, drawEffect);
1282 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1283 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001284}
1285
1286///////////////////////////////////////////////////////////////////////////////
1287
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001288GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1289 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001290 fKS(ks),
1291 fShininess(shininess) {
1292}
1293
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001294const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1295 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001296}
1297
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001298bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001299 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001300 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001301 this->ks() == s.ks() &&
1302 this->shininess() == s.shininess();
1303}
1304
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001305GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001306
bsalomon@google.com73a96942013-02-13 16:31:19 +00001307GrEffectRef* GrSpecularLightingEffect::TestCreate(SkMWCRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001308 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001309 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001310 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001311 SkScalar surfaceScale = random->nextSScalar1();
1312 SkScalar ks = random->nextUScalar1();
1313 SkScalar shininess = random->nextUScalar1();
1314 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001315 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1316 light, surfaceScale, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001317}
1318
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001319///////////////////////////////////////////////////////////////////////////////
1320
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001321GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001322 const GrDrawEffect& drawEffect)
1323 : GrGLLightingEffect(factory, drawEffect)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001324 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001325 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001326}
1327
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001328void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001329 const char* ks;
1330 const char* shininess;
1331
1332 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1333 kFloat_GrSLType, "KS", &ks);
1334 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1335 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001336
1337 static const GrGLShaderVar gLightArgs[] = {
1338 GrGLShaderVar("normal", kVec3f_GrSLType),
1339 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1340 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1341 };
1342 SkString lightBody;
1343 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1344 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001345 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1346 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001347 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1348 kVec4f_GrSLType,
1349 "light",
1350 SK_ARRAY_COUNT(gLightArgs),
1351 gLightArgs,
1352 lightBody.c_str(),
1353 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001354}
1355
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001356void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001357 const GrDrawEffect& drawEffect) {
1358 INHERITED::setData(uman, drawEffect);
1359 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1360 uman.set1f(fKSUni, spec.ks());
1361 uman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001362}
1363
1364///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001365void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001366 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001367 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001368}
1369
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001370void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1371 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001372 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001373}
1374
bsalomon@google.comc7818882013-03-20 19:19:53 +00001375void GrGLLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001376 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001377}
1378
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001379///////////////////////////////////////////////////////////////////////////////
1380
bsalomon@google.com706f6682012-10-23 14:53:55 +00001381void GrGLDistantLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
1382 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001383 SkASSERT(light->type() == SkLight::kDistant_LightType);
1384 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001385 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001386}
1387
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001388void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001389 const char* dir;
1390 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1391 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001392 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001393}
1394
1395///////////////////////////////////////////////////////////////////////////////
1396
bsalomon@google.comc7818882013-03-20 19:19:53 +00001397void GrGLPointLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001398 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001399 SkASSERT(light->type() == SkLight::kPoint_LightType);
1400 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001401 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001402}
1403
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001404void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001405 const char* loc;
1406 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1407 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001408 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001409}
1410
1411///////////////////////////////////////////////////////////////////////////////
1412
bsalomon@google.comc7818882013-03-20 19:19:53 +00001413void GrGLSpotLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001414 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001415 SkASSERT(light->type() == SkLight::kSpot_LightType);
1416 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001417 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001418 uman.set1f(fExponentUni, spotLight->specularExponent());
1419 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1420 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1421 uman.set1f(fConeScaleUni, spotLight->coneScale());
1422 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001423}
1424
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001425void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001426 const char* location;
1427 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1428 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001429 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1430 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001431}
1432
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001433void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1434 const char *surfaceToLight) {
1435
1436 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1437
1438 const char* exponent;
1439 const char* cosInner;
1440 const char* cosOuter;
1441 const char* coneScale;
1442 const char* s;
1443 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1444 kFloat_GrSLType, "Exponent", &exponent);
1445 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1446 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1447 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1448 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1449 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1450 kFloat_GrSLType, "ConeScale", &coneScale);
1451 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1452 kVec3f_GrSLType, "S", &s);
1453
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001454 static const GrGLShaderVar gLightColorArgs[] = {
1455 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1456 };
1457 SkString lightColorBody;
1458 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1459 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1460 lightColorBody.appendf("\t\treturn vec3(0);\n");
1461 lightColorBody.appendf("\t}\n");
1462 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1463 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1464 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1465 color, cosOuter, coneScale);
1466 lightColorBody.appendf("\t}\n");
1467 lightColorBody.appendf("\treturn %s;\n", color);
1468 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1469 kVec3f_GrSLType,
1470 "lightColor",
1471 SK_ARRAY_COUNT(gLightColorArgs),
1472 gLightColorArgs,
1473 lightColorBody.c_str(),
1474 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001475
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001476 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001477}
1478
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001479#endif
1480
djsollen@google.com08337772012-06-26 14:33:13 +00001481SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1482 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1483 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1484 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1485 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1486 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1487SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END