blob: 25c92b78359127d05e89537595b26d55901b6511 [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);
433 fLight->ref();
434}
435
436SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
437 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
438 SkScalar kd) {
439 return new SkDiffuseLightingImageFilter(
440 new SkDistantLight(direction), lightColor, surfaceScale, kd);
441}
442
443SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
444 SkPoint3& location, const SkColor& lightColor, SkScalar surfaceScale,
445 SkScalar kd) {
446 return new SkDiffuseLightingImageFilter(
447 new SkPointLight(location), lightColor, surfaceScale, kd);
448}
449
450SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
451 const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent,
452 SkScalar cutoffAngle, const SkColor& lightColor, SkScalar surfaceScale,
453 SkScalar kd) {
454 return new SkDiffuseLightingImageFilter(
455 new SkSpotLight(location, target, specularExponent, cutoffAngle),
456 lightColor, surfaceScale, kd);
457}
458
459SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
460 const SkPoint3& direction, const SkColor& lightColor, SkScalar surfaceScale,
461 SkScalar ks, SkScalar shininess) {
462 return new SkSpecularLightingImageFilter(
463 new SkDistantLight(direction), lightColor, surfaceScale, ks, shininess);
464}
465
466SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
467 SkPoint3& location,
468 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
469 SkScalar shininess) {
470 return new SkSpecularLightingImageFilter(
471 new SkPointLight(location), lightColor, surfaceScale, ks, shininess);
472}
473
474SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
475 const SkPoint3& location,
476 const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle,
477 const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks,
478 SkScalar shininess) {
479 return new SkSpecularLightingImageFilter(
480 new SkSpotLight(location, target, specularExponent, cutoffAngle),
481 lightColor, surfaceScale, ks, shininess);
482}
483
484SkLightingImageFilter::~SkLightingImageFilter() {
485 fLight->unref();
486}
487
488SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
489 : INHERITED(buffer)
490{
djsollen@google.com08337772012-06-26 14:33:13 +0000491 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000492 fLightColor = readPoint3(buffer);
493 fSurfaceScale = buffer.readScalar();
494}
495
496void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
497 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000498 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000499 writePoint3(fLightColor, buffer);
500 buffer.writeScalar(fSurfaceScale);
501}
502
503SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar kd)
504 : SkLightingImageFilter(light, lightColor, surfaceScale),
505 fKD(kd)
506{
507}
508
509SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
510 : INHERITED(buffer)
511{
512 fKD = buffer.readScalar();
513}
514
515void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
516 this->INHERITED::flatten(buffer);
517 buffer.writeScalar(fKD);
518}
519
520bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
521 const SkBitmap& src,
522 const SkMatrix&,
523 SkBitmap* dst,
524 SkIPoint*) {
525 if (src.config() != SkBitmap::kARGB_8888_Config) {
526 return false;
527 }
528 SkAutoLockPixels alp(src);
529 if (!src.getPixels()) {
530 return false;
531 }
532 if (src.width() < 2 || src.height() < 2) {
533 return false;
534 }
535 dst->setConfig(src.config(), src.width(), src.height());
536 dst->allocPixels();
537
538 DiffuseLightingType lightingType(fKD);
539 switch (light()->type()) {
540 case SkLight::kDistant_LightType:
541 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
542 break;
543 case SkLight::kPoint_LightType:
544 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
545 break;
546 case SkLight::kSpot_LightType:
547 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
548 break;
549 }
550 return true;
551}
552
553SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, const SkColor& lightColor, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
554 : SkLightingImageFilter(light, lightColor, surfaceScale),
555 fKS(ks),
556 fShininess(shininess)
557{
558}
559
560SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
561 : INHERITED(buffer)
562{
563 fKS = buffer.readScalar();
564 fShininess = buffer.readScalar();
565}
566
567void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
568 this->INHERITED::flatten(buffer);
569 buffer.writeScalar(fKS);
570 buffer.writeScalar(fShininess);
571}
572
573bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
574 const SkBitmap& src,
575 const SkMatrix&,
576 SkBitmap* dst,
577 SkIPoint*) {
578 if (src.config() != SkBitmap::kARGB_8888_Config) {
579 return false;
580 }
581 SkAutoLockPixels alp(src);
582 if (!src.getPixels()) {
583 return false;
584 }
585 if (src.width() < 2 || src.height() < 2) {
586 return false;
587 }
588 dst->setConfig(src.config(), src.width(), src.height());
589 dst->allocPixels();
590
591 SpecularLightingType lightingType(fKS, fShininess);
592 switch (light()->type()) {
593 case SkLight::kDistant_LightType:
594 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
595 break;
596 case SkLight::kPoint_LightType:
597 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
598 break;
599 case SkLight::kSpot_LightType:
600 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, lightColor(), surfaceScale());
601 break;
602 }
603 return true;
604}
605
djsollen@google.com08337772012-06-26 14:33:13 +0000606SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
607 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
608 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
609 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
610 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
611 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
612SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END