blob: c4a68960af1f9dd8a2dc1ff950f5c9a8881b9a0e [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"
11
12// FIXME: Eventually, this should be implemented properly, and put in
13// SkScalar.h.
14#define SkScalarPow(x, y) SkFloatToScalar(powf(SkScalarToFloat(x), SkScalarToFloat(y)))
15namespace {
16
17const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
18const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
19const SkScalar gOneHalf = SkFloatToScalar(0.5f);
20const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
21
22// Shift matrix components to the left, as we advance pixels to the right.
23inline void shiftMatrixLeft(int m[9]) {
24 m[0] = m[1];
25 m[3] = m[4];
26 m[6] = m[7];
27 m[1] = m[2];
28 m[4] = m[5];
29 m[7] = m[8];
30}
31
32class DiffuseLightingType {
33public:
34 DiffuseLightingType(SkScalar kd)
35 : fKD(kd) {}
36 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
37 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
38 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
39 SkPoint3 color(lightColor * colorScale);
40 return SkPackARGB32(255,
41 SkScalarFloorToInt(color.fX),
42 SkScalarFloorToInt(color.fY),
43 SkScalarFloorToInt(color.fZ));
44 }
45private:
46 SkScalar fKD;
47};
48
49class SpecularLightingType {
50public:
51 SpecularLightingType(SkScalar ks, SkScalar shininess)
52 : fKS(ks), fShininess(shininess) {}
53 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
54 SkPoint3 halfDir(surfaceTolight);
55 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
56 halfDir.normalize();
57 SkScalar colorScale = SkScalarMul(fKS,
58 SkScalarPow(normal.dot(halfDir), fShininess));
59 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
60 SkPoint3 color(lightColor * colorScale);
61 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
62 SkScalarFloorToInt(color.fX),
63 SkScalarFloorToInt(color.fY),
64 SkScalarFloorToInt(color.fZ));
65 }
66private:
67 SkScalar fKS;
68 SkScalar fShininess;
69};
70
71inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
72 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
73}
74
75inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
76 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
77 SkScalarMul(-y, surfaceScale),
78 SK_Scalar1);
79 vector.normalize();
80 return vector;
81}
82
83inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
84 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
85 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
86 surfaceScale);
87}
88
89inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
90 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
91 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
92 surfaceScale);
93}
94
95inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
96 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
97 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
98 surfaceScale);
99}
100
101inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
102 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
103 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
104 surfaceScale);
105}
106
107
108inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
109 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
110 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
111 surfaceScale);
112}
113
114inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
116 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
117 surfaceScale);
118}
119
120inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
122 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
123 surfaceScale);
124}
125
126inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
128 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
129 surfaceScale);
130}
131
132inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
134 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
135 surfaceScale);
136}
137
138template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, const SkPoint3& lightColor, SkScalar surfaceScale) {
139 const LightType* l = static_cast<const LightType*>(light);
140 int y = 0;
141 {
142 const SkPMColor* row1 = src.getAddr32(0, 0);
143 const SkPMColor* row2 = src.getAddr32(0, 1);
144 SkPMColor* dptr = dst->getAddr32(0, 0);
145 int m[9];
146 int x = 0;
147 m[4] = SkGetPackedA32(*row1++);
148 m[5] = SkGetPackedA32(*row1++);
149 m[7] = SkGetPackedA32(*row2++);
150 m[8] = SkGetPackedA32(*row2++);
151 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
152 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
153 for (x = 1; x < src.width() - 1; ++x)
154 {
155 shiftMatrixLeft(m);
156 m[5] = SkGetPackedA32(*row1++);
157 m[8] = SkGetPackedA32(*row2++);
158 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
159 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
160 }
161 shiftMatrixLeft(m);
162 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
163 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
164 }
165
166 for (++y; y < src.height() - 1; ++y) {
167 const SkPMColor* row0 = src.getAddr32(0, y - 1);
168 const SkPMColor* row1 = src.getAddr32(0, y);
169 const SkPMColor* row2 = src.getAddr32(0, y + 1);
170 SkPMColor* dptr = dst->getAddr32(0, y);
171 int m[9];
172 int x = 0;
173 m[1] = SkGetPackedA32(*row0++);
174 m[2] = SkGetPackedA32(*row0++);
175 m[4] = SkGetPackedA32(*row1++);
176 m[5] = SkGetPackedA32(*row1++);
177 m[7] = SkGetPackedA32(*row2++);
178 m[8] = SkGetPackedA32(*row2++);
179 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
180 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
181 for (x = 1; x < src.width() - 1; ++x) {
182 shiftMatrixLeft(m);
183 m[2] = SkGetPackedA32(*row0++);
184 m[5] = SkGetPackedA32(*row1++);
185 m[8] = SkGetPackedA32(*row2++);
186 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
187 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
188 }
189 shiftMatrixLeft(m);
190 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
191 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
192 }
193
194 {
195 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
196 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
197 int x = 0;
198 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
199 int m[9];
200 m[1] = SkGetPackedA32(*row0++);
201 m[2] = SkGetPackedA32(*row0++);
202 m[4] = SkGetPackedA32(*row1++);
203 m[5] = SkGetPackedA32(*row1++);
204 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
205 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
206 for (x = 1; x < src.width() - 1; ++x)
207 {
208 shiftMatrixLeft(m);
209 m[2] = SkGetPackedA32(*row0++);
210 m[5] = SkGetPackedA32(*row1++);
211 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
212 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
213 }
214 shiftMatrixLeft(m);
215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
216 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, lightColor * l->lightColorScale(surfaceToLight));
217 }
218}
219
220SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
221 SkPoint3 point;
222 point.fX = buffer.readScalar();
223 point.fY = buffer.readScalar();
224 point.fZ = buffer.readScalar();
225 return point;
226};
227
228void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
229 buffer.writeScalar(point.fX);
230 buffer.writeScalar(point.fY);
231 buffer.writeScalar(point.fZ);
232};
233
234class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
235public:
236 SkDiffuseLightingImageFilter(SkLight* light, const SkColor& lightColor,
237 SkScalar surfaceScale, SkScalar kd);
238 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
239
240protected:
241 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
242 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
243 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
244 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
245
246
247private:
248 typedef SkLightingImageFilter INHERITED;
249 SkScalar fKD;
250};
251
252class SkSpecularLightingImageFilter : public SkLightingImageFilter {
253public:
254 SkSpecularLightingImageFilter(SkLight* light, const SkColor& lightColor,
255 SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
256 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
257
258protected:
259 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
260 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
261 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
262 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
263
264private:
265 typedef SkLightingImageFilter INHERITED;
266 SkScalar fKS;
267 SkScalar fShininess;
268};
269
270};
271
272class SkLight : public SkFlattenable {
273public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000274 SK_DECLARE_INST_COUNT(SkLight)
275
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000276 enum LightType {
277 kDistant_LightType,
278 kPoint_LightType,
279 kSpot_LightType,
280 };
281 virtual LightType type() const = 0;
282
djsollen@google.com08337772012-06-26 14:33:13 +0000283protected:
284 SkLight() {}
285 SkLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000287 INHERITED::flatten(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000288 }
djsollen@google.com08337772012-06-26 14:33:13 +0000289
290private:
291 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000292};
293
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000294SK_DEFINE_INST_COUNT(SkLight)
295
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000296class SkDistantLight : public SkLight {
297public:
298 SkDistantLight(const SkPoint3& direction) : fDirection(direction) {
299 }
djsollen@google.com08337772012-06-26 14:33:13 +0000300
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000301 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
302 return fDirection;
303 };
304 SkScalar lightColorScale(const SkPoint3&) const { return SK_Scalar1; }
305 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000306
307 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
308
djsollen@google.com08337772012-06-26 14:33:13 +0000309protected:
310 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
311 fDirection = readPoint3(buffer);
312 }
313 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
314 INHERITED::flatten(buffer);
315 writePoint3(fDirection, buffer);
316 }
317
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000318private:
djsollen@google.com08337772012-06-26 14:33:13 +0000319 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000320 SkPoint3 fDirection;
321};
322
323class SkPointLight : public SkLight {
324public:
325 SkPointLight(const SkPoint3& location)
326 : fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000327
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000328 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
329 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
330 fLocation.fY - SkIntToScalar(y),
331 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
332 direction.normalize();
333 return direction;
334 };
335 SkScalar lightColorScale(const SkPoint3&) const { return SK_Scalar1; }
336 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000337
338 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
339
djsollen@google.com08337772012-06-26 14:33:13 +0000340protected:
341 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
342 fLocation = readPoint3(buffer);
343 }
344 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
345 INHERITED::flatten(buffer);
346 writePoint3(fLocation, buffer);
347 }
348
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000349private:
djsollen@google.com08337772012-06-26 14:33:13 +0000350 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000351 SkPoint3 fLocation;
352};
353
354class SkSpotLight : public SkLight {
355public:
356 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle)
357 : fLocation(location),
358 fTarget(target),
359 fSpecularExponent(specularExponent)
360 {
361 fS = target - location;
362 fS.normalize();
363 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
364 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
365 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
366 fConeScale = SkScalarInvert(antiAliasThreshold);
367 }
djsollen@google.com08337772012-06-26 14:33:13 +0000368
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000369 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
370 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
371 fLocation.fY - SkIntToScalar(y),
372 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
373 direction.normalize();
374 return direction;
375 };
376 SkScalar lightColorScale(const SkPoint3& surfaceToLight) const {
377 SkScalar cosAngle = -surfaceToLight.dot(fS);
378 if (cosAngle < fCosOuterConeAngle) {
379 return 0;
380 }
381 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
382 if (cosAngle < fCosInnerConeAngle) {
383 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
384 return SkScalarMul(scale, fConeScale);
385 }
386 return scale;
387 }
388
djsollen@google.com08337772012-06-26 14:33:13 +0000389 virtual LightType type() const { return kSpot_LightType; }
390
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000391 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
392
djsollen@google.com08337772012-06-26 14:33:13 +0000393protected:
394 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
395 fLocation = readPoint3(buffer);
396 fTarget = readPoint3(buffer);
397 fSpecularExponent = buffer.readScalar();
398 fCosOuterConeAngle = buffer.readScalar();
399 fCosInnerConeAngle = buffer.readScalar();
400 fConeScale = buffer.readScalar();
401 fS = readPoint3(buffer);
402 }
403 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
404 INHERITED::flatten(buffer);
405 writePoint3(fLocation, buffer);
406 writePoint3(fTarget, buffer);
407 buffer.writeScalar(fSpecularExponent);
408 buffer.writeScalar(fCosOuterConeAngle);
409 buffer.writeScalar(fCosInnerConeAngle);
410 buffer.writeScalar(fConeScale);
411 writePoint3(fS, buffer);
412 }
413
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000414private:
djsollen@google.com08337772012-06-26 14:33:13 +0000415 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000416 SkPoint3 fLocation;
417 SkPoint3 fTarget;
418 SkScalar fSpecularExponent;
419 SkScalar fCosOuterConeAngle;
420 SkScalar fCosInnerConeAngle;
421 SkScalar fConeScale;
422 SkPoint3 fS;
423};
424
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000425SkLightingImageFilter::SkLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale)
426 : fLight(light),
427 fLightColor(SkIntToScalar(SkColorGetR(lightColor)),
428 SkIntToScalar(SkColorGetG(lightColor)),
429 SkIntToScalar(SkColorGetB(lightColor))),
430 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
431{
432 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000433 // our caller knows that we take ownership of the light, so we don't
434 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000435}
436
437SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
438 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
439 SkScalar kd) {
440 return new SkDiffuseLightingImageFilter(
441 new SkDistantLight(direction), lightColor, surfaceScale, kd);
442}
443
444SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
445 SkPoint3& location, const SkColor& lightColor, SkScalar surfaceScale,
446 SkScalar kd) {
447 return new SkDiffuseLightingImageFilter(
448 new SkPointLight(location), lightColor, surfaceScale, kd);
449}
450
451SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
452 const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent,
453 SkScalar cutoffAngle, const SkColor& lightColor, SkScalar surfaceScale,
454 SkScalar kd) {
455 return new SkDiffuseLightingImageFilter(
456 new SkSpotLight(location, target, specularExponent, cutoffAngle),
457 lightColor, surfaceScale, kd);
458}
459
460SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
461 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
462 SkScalar ks, SkScalar shininess) {
463 return new SkSpecularLightingImageFilter(
464 new SkDistantLight(direction), lightColor, surfaceScale, ks, shininess);
465}
466
467SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
468 SkPoint3& location,
469 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
470 SkScalar shininess) {
471 return new SkSpecularLightingImageFilter(
472 new SkPointLight(location), lightColor, surfaceScale, ks, shininess);
473}
474
475SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
476 const SkPoint3& location,
477 const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle,
478 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
479 SkScalar shininess) {
480 return new SkSpecularLightingImageFilter(
481 new SkSpotLight(location, target, specularExponent, cutoffAngle),
482 lightColor, surfaceScale, ks, shininess);
483}
484
485SkLightingImageFilter::~SkLightingImageFilter() {
486 fLight->unref();
487}
488
489SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
490 : INHERITED(buffer)
491{
djsollen@google.com08337772012-06-26 14:33:13 +0000492 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000493 fLightColor = readPoint3(buffer);
494 fSurfaceScale = buffer.readScalar();
495}
496
497void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
498 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000499 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000500 writePoint3(fLightColor, buffer);
501 buffer.writeScalar(fSurfaceScale);
502}
503
504SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar kd)
505 : SkLightingImageFilter(light, lightColor, surfaceScale),
506 fKD(kd)
507{
508}
509
510SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
511 : INHERITED(buffer)
512{
513 fKD = buffer.readScalar();
514}
515
516void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
517 this->INHERITED::flatten(buffer);
518 buffer.writeScalar(fKD);
519}
520
521bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
522 const SkBitmap& src,
523 const SkMatrix&,
524 SkBitmap* dst,
525 SkIPoint*) {
526 if (src.config() != SkBitmap::kARGB_8888_Config) {
527 return false;
528 }
529 SkAutoLockPixels alp(src);
530 if (!src.getPixels()) {
531 return false;
532 }
533 if (src.width() < 2 || src.height() < 2) {
534 return false;
535 }
536 dst->setConfig(src.config(), src.width(), src.height());
537 dst->allocPixels();
538
539 DiffuseLightingType lightingType(fKD);
540 switch (light()->type()) {
541 case SkLight::kDistant_LightType:
542 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
543 break;
544 case SkLight::kPoint_LightType:
545 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
546 break;
547 case SkLight::kSpot_LightType:
548 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
549 break;
550 }
551 return true;
552}
553
554SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
555 : SkLightingImageFilter(light, lightColor, surfaceScale),
556 fKS(ks),
557 fShininess(shininess)
558{
559}
560
561SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
562 : INHERITED(buffer)
563{
564 fKS = buffer.readScalar();
565 fShininess = buffer.readScalar();
566}
567
568void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
569 this->INHERITED::flatten(buffer);
570 buffer.writeScalar(fKS);
571 buffer.writeScalar(fShininess);
572}
573
574bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
575 const SkBitmap& src,
576 const SkMatrix&,
577 SkBitmap* dst,
578 SkIPoint*) {
579 if (src.config() != SkBitmap::kARGB_8888_Config) {
580 return false;
581 }
582 SkAutoLockPixels alp(src);
583 if (!src.getPixels()) {
584 return false;
585 }
586 if (src.width() < 2 || src.height() < 2) {
587 return false;
588 }
589 dst->setConfig(src.config(), src.width(), src.height());
590 dst->allocPixels();
591
592 SpecularLightingType lightingType(fKS, fShininess);
593 switch (light()->type()) {
594 case SkLight::kDistant_LightType:
595 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
596 break;
597 case SkLight::kPoint_LightType:
598 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
599 break;
600 case SkLight::kSpot_LightType:
601 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
602 break;
603 }
604 return true;
605}
606
djsollen@google.com08337772012-06-26 14:33:13 +0000607SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
608 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
609 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
610 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
611 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
612 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
613SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END