blob: 84cb2910b300dbbbdcab102f6d2aabd3a9e7b50d [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:
274 enum LightType {
275 kDistant_LightType,
276 kPoint_LightType,
277 kSpot_LightType,
278 };
279 virtual LightType type() const = 0;
280
djsollen@google.com08337772012-06-26 14:33:13 +0000281protected:
282 SkLight() {}
283 SkLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000284 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000285 INHERITED::flatten(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 }
djsollen@google.com08337772012-06-26 14:33:13 +0000287
288private:
289 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290};
291
292class SkDistantLight : public SkLight {
293public:
294 SkDistantLight(const SkPoint3& direction) : fDirection(direction) {
295 }
djsollen@google.com08337772012-06-26 14:33:13 +0000296
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
298 return fDirection;
299 };
300 SkScalar lightColorScale(const SkPoint3&) const { return SK_Scalar1; }
301 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000302
303 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
304
djsollen@google.com08337772012-06-26 14:33:13 +0000305protected:
306 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
307 fDirection = readPoint3(buffer);
308 }
309 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
310 INHERITED::flatten(buffer);
311 writePoint3(fDirection, buffer);
312 }
313
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000314private:
djsollen@google.com08337772012-06-26 14:33:13 +0000315 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000316 SkPoint3 fDirection;
317};
318
319class SkPointLight : public SkLight {
320public:
321 SkPointLight(const SkPoint3& location)
322 : fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000323
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000324 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
325 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
326 fLocation.fY - SkIntToScalar(y),
327 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
328 direction.normalize();
329 return direction;
330 };
331 SkScalar lightColorScale(const SkPoint3&) const { return SK_Scalar1; }
332 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000333
334 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
335
djsollen@google.com08337772012-06-26 14:33:13 +0000336protected:
337 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
338 fLocation = readPoint3(buffer);
339 }
340 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
341 INHERITED::flatten(buffer);
342 writePoint3(fLocation, buffer);
343 }
344
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000345private:
djsollen@google.com08337772012-06-26 14:33:13 +0000346 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000347 SkPoint3 fLocation;
348};
349
350class SkSpotLight : public SkLight {
351public:
352 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle)
353 : fLocation(location),
354 fTarget(target),
355 fSpecularExponent(specularExponent)
356 {
357 fS = target - location;
358 fS.normalize();
359 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
360 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
361 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
362 fConeScale = SkScalarInvert(antiAliasThreshold);
363 }
djsollen@google.com08337772012-06-26 14:33:13 +0000364
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000365 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
366 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
367 fLocation.fY - SkIntToScalar(y),
368 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
369 direction.normalize();
370 return direction;
371 };
372 SkScalar lightColorScale(const SkPoint3& surfaceToLight) const {
373 SkScalar cosAngle = -surfaceToLight.dot(fS);
374 if (cosAngle < fCosOuterConeAngle) {
375 return 0;
376 }
377 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
378 if (cosAngle < fCosInnerConeAngle) {
379 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
380 return SkScalarMul(scale, fConeScale);
381 }
382 return scale;
383 }
384
djsollen@google.com08337772012-06-26 14:33:13 +0000385 virtual LightType type() const { return kSpot_LightType; }
386
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000387 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
388
djsollen@google.com08337772012-06-26 14:33:13 +0000389protected:
390 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
391 fLocation = readPoint3(buffer);
392 fTarget = readPoint3(buffer);
393 fSpecularExponent = buffer.readScalar();
394 fCosOuterConeAngle = buffer.readScalar();
395 fCosInnerConeAngle = buffer.readScalar();
396 fConeScale = buffer.readScalar();
397 fS = readPoint3(buffer);
398 }
399 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
400 INHERITED::flatten(buffer);
401 writePoint3(fLocation, buffer);
402 writePoint3(fTarget, buffer);
403 buffer.writeScalar(fSpecularExponent);
404 buffer.writeScalar(fCosOuterConeAngle);
405 buffer.writeScalar(fCosInnerConeAngle);
406 buffer.writeScalar(fConeScale);
407 writePoint3(fS, buffer);
408 }
409
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000410private:
djsollen@google.com08337772012-06-26 14:33:13 +0000411 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000412 SkPoint3 fLocation;
413 SkPoint3 fTarget;
414 SkScalar fSpecularExponent;
415 SkScalar fCosOuterConeAngle;
416 SkScalar fCosInnerConeAngle;
417 SkScalar fConeScale;
418 SkPoint3 fS;
419};
420
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000421SkLightingImageFilter::SkLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale)
422 : fLight(light),
423 fLightColor(SkIntToScalar(SkColorGetR(lightColor)),
424 SkIntToScalar(SkColorGetG(lightColor)),
425 SkIntToScalar(SkColorGetB(lightColor))),
426 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
427{
428 SkASSERT(fLight);
429 fLight->ref();
430}
431
432SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
433 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
434 SkScalar kd) {
435 return new SkDiffuseLightingImageFilter(
436 new SkDistantLight(direction), lightColor, surfaceScale, kd);
437}
438
439SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
440 SkPoint3& location, const SkColor& lightColor, SkScalar surfaceScale,
441 SkScalar kd) {
442 return new SkDiffuseLightingImageFilter(
443 new SkPointLight(location), lightColor, surfaceScale, kd);
444}
445
446SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
447 const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent,
448 SkScalar cutoffAngle, const SkColor& lightColor, SkScalar surfaceScale,
449 SkScalar kd) {
450 return new SkDiffuseLightingImageFilter(
451 new SkSpotLight(location, target, specularExponent, cutoffAngle),
452 lightColor, surfaceScale, kd);
453}
454
455SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
456 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
457 SkScalar ks, SkScalar shininess) {
458 return new SkSpecularLightingImageFilter(
459 new SkDistantLight(direction), lightColor, surfaceScale, ks, shininess);
460}
461
462SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
463 SkPoint3& location,
464 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
465 SkScalar shininess) {
466 return new SkSpecularLightingImageFilter(
467 new SkPointLight(location), lightColor, surfaceScale, ks, shininess);
468}
469
470SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
471 const SkPoint3& location,
472 const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle,
473 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
474 SkScalar shininess) {
475 return new SkSpecularLightingImageFilter(
476 new SkSpotLight(location, target, specularExponent, cutoffAngle),
477 lightColor, surfaceScale, ks, shininess);
478}
479
480SkLightingImageFilter::~SkLightingImageFilter() {
481 fLight->unref();
482}
483
484SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
485 : INHERITED(buffer)
486{
djsollen@google.com08337772012-06-26 14:33:13 +0000487 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000488 fLightColor = readPoint3(buffer);
489 fSurfaceScale = buffer.readScalar();
490}
491
492void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
493 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000494 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000495 writePoint3(fLightColor, buffer);
496 buffer.writeScalar(fSurfaceScale);
497}
498
499SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar kd)
500 : SkLightingImageFilter(light, lightColor, surfaceScale),
501 fKD(kd)
502{
503}
504
505SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
506 : INHERITED(buffer)
507{
508 fKD = buffer.readScalar();
509}
510
511void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
512 this->INHERITED::flatten(buffer);
513 buffer.writeScalar(fKD);
514}
515
516bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
517 const SkBitmap& src,
518 const SkMatrix&,
519 SkBitmap* dst,
520 SkIPoint*) {
521 if (src.config() != SkBitmap::kARGB_8888_Config) {
522 return false;
523 }
524 SkAutoLockPixels alp(src);
525 if (!src.getPixels()) {
526 return false;
527 }
528 if (src.width() < 2 || src.height() < 2) {
529 return false;
530 }
531 dst->setConfig(src.config(), src.width(), src.height());
532 dst->allocPixels();
533
534 DiffuseLightingType lightingType(fKD);
535 switch (light()->type()) {
536 case SkLight::kDistant_LightType:
537 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
538 break;
539 case SkLight::kPoint_LightType:
540 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
541 break;
542 case SkLight::kSpot_LightType:
543 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
544 break;
545 }
546 return true;
547}
548
549SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
550 : SkLightingImageFilter(light, lightColor, surfaceScale),
551 fKS(ks),
552 fShininess(shininess)
553{
554}
555
556SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
557 : INHERITED(buffer)
558{
559 fKS = buffer.readScalar();
560 fShininess = buffer.readScalar();
561}
562
563void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
564 this->INHERITED::flatten(buffer);
565 buffer.writeScalar(fKS);
566 buffer.writeScalar(fShininess);
567}
568
569bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
570 const SkBitmap& src,
571 const SkMatrix&,
572 SkBitmap* dst,
573 SkIPoint*) {
574 if (src.config() != SkBitmap::kARGB_8888_Config) {
575 return false;
576 }
577 SkAutoLockPixels alp(src);
578 if (!src.getPixels()) {
579 return false;
580 }
581 if (src.width() < 2 || src.height() < 2) {
582 return false;
583 }
584 dst->setConfig(src.config(), src.width(), src.height());
585 dst->allocPixels();
586
587 SpecularLightingType lightingType(fKS, fShininess);
588 switch (light()->type()) {
589 case SkLight::kDistant_LightType:
590 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
591 break;
592 case SkLight::kPoint_LightType:
593 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
594 break;
595 case SkLight::kSpot_LightType:
596 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
597 break;
598 }
599 return true;
600}
601
djsollen@google.com08337772012-06-26 14:33:13 +0000602SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
603 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
604 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
605 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
606 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
607 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
608SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END