blob: 5625d0363db542b9b102686f5024493c1e3e2847 [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
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000138template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000139 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);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000152 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000153 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);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000159 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000160 }
161 shiftMatrixLeft(m);
162 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000163 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000164 }
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);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000180 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000181 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);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000187 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 }
189 shiftMatrixLeft(m);
190 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000191 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000192 }
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);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000205 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000206 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);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000212 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000213 }
214 shiftMatrixLeft(m);
215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000216 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000217 }
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:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000236 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000237 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
238
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000239 SkScalar kd() const { return fKD; }
240
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000241protected:
242 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
243 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
244 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
245 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
246
247
248private:
249 typedef SkLightingImageFilter INHERITED;
250 SkScalar fKD;
251};
252
253class SkSpecularLightingImageFilter : public SkLightingImageFilter {
254public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000255 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000256 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;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000282 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000283
djsollen@google.com08337772012-06-26 14:33:13 +0000284protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000285 SkLight(SkColor color)
286 : fColor(SkIntToScalar(SkColorGetR(color)),
287 SkIntToScalar(SkColorGetG(color)),
288 SkIntToScalar(SkColorGetB(color))) {}
289 SkLight(SkFlattenableReadBuffer& buffer)
290 : INHERITED(buffer) {
291 fColor = readPoint3(buffer);
292 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000293 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000294 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000295 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000296 }
djsollen@google.com08337772012-06-26 14:33:13 +0000297
298private:
299 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000300 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000301};
302
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000303SK_DEFINE_INST_COUNT(SkLight)
304
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000305class SkDistantLight : public SkLight {
306public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000307 SkDistantLight(const SkPoint3& direction, SkColor color)
308 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000309 }
djsollen@google.com08337772012-06-26 14:33:13 +0000310
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000311 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
312 return fDirection;
313 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000314 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000315 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000316 SkPoint3 direction() const { return fDirection; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000317
318 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
319
djsollen@google.com08337772012-06-26 14:33:13 +0000320protected:
321 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
322 fDirection = readPoint3(buffer);
323 }
324 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
325 INHERITED::flatten(buffer);
326 writePoint3(fDirection, buffer);
327 }
328
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000329private:
djsollen@google.com08337772012-06-26 14:33:13 +0000330 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000331 SkPoint3 fDirection;
332};
333
334class SkPointLight : public SkLight {
335public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000336 SkPointLight(const SkPoint3& location, SkColor color)
337 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000338
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000339 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
340 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
341 fLocation.fY - SkIntToScalar(y),
342 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
343 direction.normalize();
344 return direction;
345 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000346 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000347 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000348
349 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
350
djsollen@google.com08337772012-06-26 14:33:13 +0000351protected:
352 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
353 fLocation = readPoint3(buffer);
354 }
355 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
356 INHERITED::flatten(buffer);
357 writePoint3(fLocation, buffer);
358 }
359
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000360private:
djsollen@google.com08337772012-06-26 14:33:13 +0000361 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000362 SkPoint3 fLocation;
363};
364
365class SkSpotLight : public SkLight {
366public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000367 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
368 : INHERITED(color),
369 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000370 fTarget(target),
371 fSpecularExponent(specularExponent)
372 {
373 fS = target - location;
374 fS.normalize();
375 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
376 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
377 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
378 fConeScale = SkScalarInvert(antiAliasThreshold);
379 }
djsollen@google.com08337772012-06-26 14:33:13 +0000380
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000381 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
382 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
383 fLocation.fY - SkIntToScalar(y),
384 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
385 direction.normalize();
386 return direction;
387 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000388 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000389 SkScalar cosAngle = -surfaceToLight.dot(fS);
390 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000391 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000392 }
393 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
394 if (cosAngle < fCosInnerConeAngle) {
395 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000396 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000397 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000398 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000399 }
400
djsollen@google.com08337772012-06-26 14:33:13 +0000401 virtual LightType type() const { return kSpot_LightType; }
402
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000403 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
404
djsollen@google.com08337772012-06-26 14:33:13 +0000405protected:
406 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
407 fLocation = readPoint3(buffer);
408 fTarget = readPoint3(buffer);
409 fSpecularExponent = buffer.readScalar();
410 fCosOuterConeAngle = buffer.readScalar();
411 fCosInnerConeAngle = buffer.readScalar();
412 fConeScale = buffer.readScalar();
413 fS = readPoint3(buffer);
414 }
415 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
416 INHERITED::flatten(buffer);
417 writePoint3(fLocation, buffer);
418 writePoint3(fTarget, buffer);
419 buffer.writeScalar(fSpecularExponent);
420 buffer.writeScalar(fCosOuterConeAngle);
421 buffer.writeScalar(fCosInnerConeAngle);
422 buffer.writeScalar(fConeScale);
423 writePoint3(fS, buffer);
424 }
425
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000426private:
djsollen@google.com08337772012-06-26 14:33:13 +0000427 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000428 SkPoint3 fLocation;
429 SkPoint3 fTarget;
430 SkScalar fSpecularExponent;
431 SkScalar fCosOuterConeAngle;
432 SkScalar fCosInnerConeAngle;
433 SkScalar fConeScale;
434 SkPoint3 fS;
435};
436
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000437SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000438 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000439 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
440{
441 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000442 // our caller knows that we take ownership of the light, so we don't
443 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000444}
445
446SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000447 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000448 SkScalar kd) {
449 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000450 new SkDistantLight(direction, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000451}
452
453SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000454 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000455 SkScalar kd) {
456 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000457 new SkPointLight(location, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000458}
459
460SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000461 const SkPoint3& location, const SkPoint3& target,
462 SkScalar specularExponent, SkScalar cutoffAngle,
463 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000464 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000465 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
466 surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000467}
468
469SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000470 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471 SkScalar ks, SkScalar shininess) {
472 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000473 new SkDistantLight(direction, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474}
475
476SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000477 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
478 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000480 new SkPointLight(location, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481}
482
483SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000484 const SkPoint3& location, const SkPoint3& target,
485 SkScalar specularExponent, SkScalar cutoffAngle,
486 SkColor lightColor, SkScalar surfaceScale,
487 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000488 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000489 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
490 surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000491}
492
493SkLightingImageFilter::~SkLightingImageFilter() {
494 fLight->unref();
495}
496
497SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
498 : INHERITED(buffer)
499{
djsollen@google.com08337772012-06-26 14:33:13 +0000500 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501 fSurfaceScale = buffer.readScalar();
502}
503
504void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
505 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000506 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000507 buffer.writeScalar(fSurfaceScale);
508}
509
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000510SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
511 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512 fKD(kd)
513{
514}
515
516SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
517 : INHERITED(buffer)
518{
519 fKD = buffer.readScalar();
520}
521
522void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
523 this->INHERITED::flatten(buffer);
524 buffer.writeScalar(fKD);
525}
526
527bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
528 const SkBitmap& src,
529 const SkMatrix&,
530 SkBitmap* dst,
531 SkIPoint*) {
532 if (src.config() != SkBitmap::kARGB_8888_Config) {
533 return false;
534 }
535 SkAutoLockPixels alp(src);
536 if (!src.getPixels()) {
537 return false;
538 }
539 if (src.width() < 2 || src.height() < 2) {
540 return false;
541 }
542 dst->setConfig(src.config(), src.width(), src.height());
543 dst->allocPixels();
544
545 DiffuseLightingType lightingType(fKD);
546 switch (light()->type()) {
547 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000548 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000549 break;
550 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000551 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000552 break;
553 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000554 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000555 break;
556 }
557 return true;
558}
559
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000560SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
561 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000562 fKS(ks),
563 fShininess(shininess)
564{
565}
566
567SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
568 : INHERITED(buffer)
569{
570 fKS = buffer.readScalar();
571 fShininess = buffer.readScalar();
572}
573
574void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
575 this->INHERITED::flatten(buffer);
576 buffer.writeScalar(fKS);
577 buffer.writeScalar(fShininess);
578}
579
580bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
581 const SkBitmap& src,
582 const SkMatrix&,
583 SkBitmap* dst,
584 SkIPoint*) {
585 if (src.config() != SkBitmap::kARGB_8888_Config) {
586 return false;
587 }
588 SkAutoLockPixels alp(src);
589 if (!src.getPixels()) {
590 return false;
591 }
592 if (src.width() < 2 || src.height() < 2) {
593 return false;
594 }
595 dst->setConfig(src.config(), src.width(), src.height());
596 dst->allocPixels();
597
598 SpecularLightingType lightingType(fKS, fShininess);
599 switch (light()->type()) {
600 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000601 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000602 break;
603 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000604 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000605 break;
606 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000607 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000608 break;
609 }
610 return true;
611}
612
djsollen@google.com08337772012-06-26 14:33:13 +0000613SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
614 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
615 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
616 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
617 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
618 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
619SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END