blob: c2551d138a59ff4b5d366181664bf414eb0865b2 [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
281 static SkLight* Create(SkFlattenableReadBuffer& buffer);
282 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
283 buffer.write32(type());
284 }
285};
286
287class SkDistantLight : public SkLight {
288public:
289 SkDistantLight(const SkPoint3& direction) : fDirection(direction) {
290 }
291 SkDistantLight(SkFlattenableReadBuffer& buffer) {
292 fDirection = readPoint3(buffer);
293 }
294 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
295 return fDirection;
296 };
297 SkScalar lightColorScale(const SkPoint3&) const { return SK_Scalar1; }
298 virtual LightType type() const { return kDistant_LightType; }
299 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
300 SkLight::flatten(buffer);
301 writePoint3(fDirection, buffer);
302 }
303
304 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
305
306private:
307 SkPoint3 fDirection;
308};
309
310class SkPointLight : public SkLight {
311public:
312 SkPointLight(const SkPoint3& location)
313 : fLocation(location) {}
314 SkPointLight(SkFlattenableReadBuffer& buffer) {
315 fLocation = readPoint3(buffer);
316 }
317 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
318 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
319 fLocation.fY - SkIntToScalar(y),
320 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
321 direction.normalize();
322 return direction;
323 };
324 SkScalar lightColorScale(const SkPoint3&) const { return SK_Scalar1; }
325 virtual LightType type() const { return kPoint_LightType; }
326 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
327 SkLight::flatten(buffer);
328 writePoint3(fLocation, buffer);
329 }
330
331 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
332
333private:
334 SkPoint3 fLocation;
335};
336
337class SkSpotLight : public SkLight {
338public:
339 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle)
340 : fLocation(location),
341 fTarget(target),
342 fSpecularExponent(specularExponent)
343 {
344 fS = target - location;
345 fS.normalize();
346 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
347 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
348 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
349 fConeScale = SkScalarInvert(antiAliasThreshold);
350 }
351 SkSpotLight(SkFlattenableReadBuffer& buffer) {
352 fLocation = readPoint3(buffer);
353 fTarget = readPoint3(buffer);
354 fSpecularExponent = buffer.readScalar();
355 fCosOuterConeAngle = buffer.readScalar();
356 fCosInnerConeAngle = buffer.readScalar();
357 fConeScale = buffer.readScalar();
358 fS = readPoint3(buffer);
359 }
360 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
361 SkLight::flatten(buffer);
362 writePoint3(fLocation, buffer);
363 writePoint3(fTarget, buffer);
364 buffer.writeScalar(fSpecularExponent);
365 buffer.writeScalar(fCosOuterConeAngle);
366 buffer.writeScalar(fCosInnerConeAngle);
367 buffer.writeScalar(fConeScale);
368 writePoint3(fS, buffer);
369 }
370 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
371 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
372 fLocation.fY - SkIntToScalar(y),
373 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
374 direction.normalize();
375 return direction;
376 };
377 SkScalar lightColorScale(const SkPoint3& surfaceToLight) const {
378 SkScalar cosAngle = -surfaceToLight.dot(fS);
379 if (cosAngle < fCosOuterConeAngle) {
380 return 0;
381 }
382 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
383 if (cosAngle < fCosInnerConeAngle) {
384 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
385 return SkScalarMul(scale, fConeScale);
386 }
387 return scale;
388 }
389
390 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
391
392 virtual LightType type() const { return kSpot_LightType; }
393private:
394 SkPoint3 fLocation;
395 SkPoint3 fTarget;
396 SkScalar fSpecularExponent;
397 SkScalar fCosOuterConeAngle;
398 SkScalar fCosInnerConeAngle;
399 SkScalar fConeScale;
400 SkPoint3 fS;
401};
402
403SkLight* SkLight::Create(SkFlattenableReadBuffer& buffer) {
404 LightType type = static_cast<LightType>(buffer.readU32());
405 switch (type) {
406 case kDistant_LightType:
407 return new SkDistantLight(buffer);
408 case kPoint_LightType:
409 return new SkPointLight(buffer);
410 case kSpot_LightType:
411 return new SkSpotLight(buffer);
412 default:
413 SkASSERT(false);
414 return 0;
415 }
416}
417
418SkLightingImageFilter::SkLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale)
419 : fLight(light),
420 fLightColor(SkIntToScalar(SkColorGetR(lightColor)),
421 SkIntToScalar(SkColorGetG(lightColor)),
422 SkIntToScalar(SkColorGetB(lightColor))),
423 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
424{
425 SkASSERT(fLight);
426 fLight->ref();
427}
428
429SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
430 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
431 SkScalar kd) {
432 return new SkDiffuseLightingImageFilter(
433 new SkDistantLight(direction), lightColor, surfaceScale, kd);
434}
435
436SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
437 SkPoint3& location, const SkColor& lightColor, SkScalar surfaceScale,
438 SkScalar kd) {
439 return new SkDiffuseLightingImageFilter(
440 new SkPointLight(location), lightColor, surfaceScale, kd);
441}
442
443SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
444 const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent,
445 SkScalar cutoffAngle, const SkColor& lightColor, SkScalar surfaceScale,
446 SkScalar kd) {
447 return new SkDiffuseLightingImageFilter(
448 new SkSpotLight(location, target, specularExponent, cutoffAngle),
449 lightColor, surfaceScale, kd);
450}
451
452SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
453 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
454 SkScalar ks, SkScalar shininess) {
455 return new SkSpecularLightingImageFilter(
456 new SkDistantLight(direction), lightColor, surfaceScale, ks, shininess);
457}
458
459SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
460 SkPoint3& location,
461 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
462 SkScalar shininess) {
463 return new SkSpecularLightingImageFilter(
464 new SkPointLight(location), lightColor, surfaceScale, ks, shininess);
465}
466
467SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
468 const SkPoint3& location,
469 const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle,
470 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
471 SkScalar shininess) {
472 return new SkSpecularLightingImageFilter(
473 new SkSpotLight(location, target, specularExponent, cutoffAngle),
474 lightColor, surfaceScale, ks, shininess);
475}
476
477SkLightingImageFilter::~SkLightingImageFilter() {
478 fLight->unref();
479}
480
481SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
482 : INHERITED(buffer)
483{
484 fLight = SkLight::Create(buffer);
485 fLightColor = readPoint3(buffer);
486 fSurfaceScale = buffer.readScalar();
487}
488
489void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
490 this->INHERITED::flatten(buffer);
491 fLight->flatten(buffer);
492 writePoint3(fLightColor, buffer);
493 buffer.writeScalar(fSurfaceScale);
494}
495
496SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar kd)
497 : SkLightingImageFilter(light, lightColor, surfaceScale),
498 fKD(kd)
499{
500}
501
502SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
503 : INHERITED(buffer)
504{
505 fKD = buffer.readScalar();
506}
507
508void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
509 this->INHERITED::flatten(buffer);
510 buffer.writeScalar(fKD);
511}
512
513bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
514 const SkBitmap& src,
515 const SkMatrix&,
516 SkBitmap* dst,
517 SkIPoint*) {
518 if (src.config() != SkBitmap::kARGB_8888_Config) {
519 return false;
520 }
521 SkAutoLockPixels alp(src);
522 if (!src.getPixels()) {
523 return false;
524 }
525 if (src.width() < 2 || src.height() < 2) {
526 return false;
527 }
528 dst->setConfig(src.config(), src.width(), src.height());
529 dst->allocPixels();
530
531 DiffuseLightingType lightingType(fKD);
532 switch (light()->type()) {
533 case SkLight::kDistant_LightType:
534 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
535 break;
536 case SkLight::kPoint_LightType:
537 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
538 break;
539 case SkLight::kSpot_LightType:
540 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
541 break;
542 }
543 return true;
544}
545
546SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
547 : SkLightingImageFilter(light, lightColor, surfaceScale),
548 fKS(ks),
549 fShininess(shininess)
550{
551}
552
553SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
554 : INHERITED(buffer)
555{
556 fKS = buffer.readScalar();
557 fShininess = buffer.readScalar();
558}
559
560void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
561 this->INHERITED::flatten(buffer);
562 buffer.writeScalar(fKS);
563 buffer.writeScalar(fShininess);
564}
565
566bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
567 const SkBitmap& src,
568 const SkMatrix&,
569 SkBitmap* dst,
570 SkIPoint*) {
571 if (src.config() != SkBitmap::kARGB_8888_Config) {
572 return false;
573 }
574 SkAutoLockPixels alp(src);
575 if (!src.getPixels()) {
576 return false;
577 }
578 if (src.width() < 2 || src.height() < 2) {
579 return false;
580 }
581 dst->setConfig(src.config(), src.width(), src.height());
582 dst->allocPixels();
583
584 SpecularLightingType lightingType(fKS, fShininess);
585 switch (light()->type()) {
586 case SkLight::kDistant_LightType:
587 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
588 break;
589 case SkLight::kPoint_LightType:
590 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
591 break;
592 case SkLight::kSpot_LightType:
593 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
594 break;
595 }
596 return true;
597}
598
599SK_DEFINE_FLATTENABLE_REGISTRAR(SkLightingImageFilter)