|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 #include "SkEmbossMask.h" |
|
11 #include "SkMath.h" |
|
12 |
|
13 static inline int nonzero_to_one(int x) { |
|
14 #if 0 |
|
15 return x != 0; |
|
16 #else |
|
17 return ((unsigned)(x | -x)) >> 31; |
|
18 #endif |
|
19 } |
|
20 |
|
21 static inline int neq_to_one(int x, int max) { |
|
22 #if 0 |
|
23 return x != max; |
|
24 #else |
|
25 SkASSERT(x >= 0 && x <= max); |
|
26 return ((unsigned)(x - max)) >> 31; |
|
27 #endif |
|
28 } |
|
29 |
|
30 static inline int neq_to_mask(int x, int max) { |
|
31 #if 0 |
|
32 return -(x != max); |
|
33 #else |
|
34 SkASSERT(x >= 0 && x <= max); |
|
35 return (x - max) >> 31; |
|
36 #endif |
|
37 } |
|
38 |
|
39 static inline unsigned div255(unsigned x) { |
|
40 SkASSERT(x <= (255*255)); |
|
41 return x * ((1 << 24) / 255) >> 24; |
|
42 } |
|
43 |
|
44 #define kDelta 32 // small enough to show off angle differences |
|
45 |
|
46 #include "SkEmbossMask_Table.h" |
|
47 |
|
48 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG) |
|
49 |
|
50 #include <stdio.h> |
|
51 |
|
52 void SkEmbossMask_BuildTable() { |
|
53 // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table |
|
54 |
|
55 FILE* file = ::fopen("SkEmbossMask_Table.h", "w"); |
|
56 SkASSERT(file); |
|
57 ::fprintf(file, "#include \"SkTypes.h\"\n\n"); |
|
58 ::fprintf(file, "static const U16 gInvSqrtTable[128 * 128] = {\n"); |
|
59 for (int dx = 0; dx <= 255/2; dx++) { |
|
60 for (int dy = 0; dy <= 255/2; dy++) { |
|
61 if ((dy & 15) == 0) |
|
62 ::fprintf(file, "\t"); |
|
63 |
|
64 uint16_t value = SkToU16((1 << 15) / SkSqrt32(dx * dx + dy * dy + kDelta*kDelta/4)); |
|
65 |
|
66 ::fprintf(file, "0x%04X", value); |
|
67 if (dx * 128 + dy < 128*128-1) { |
|
68 ::fprintf(file, ", "); |
|
69 } |
|
70 if ((dy & 15) == 15) { |
|
71 ::fprintf(file, "\n"); |
|
72 } |
|
73 } |
|
74 } |
|
75 ::fprintf(file, "};\n#define kDeltaUsedToBuildTable\t%d\n", kDelta); |
|
76 ::fclose(file); |
|
77 } |
|
78 |
|
79 #endif |
|
80 |
|
81 void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) { |
|
82 SkASSERT(kDelta == kDeltaUsedToBuildTable); |
|
83 |
|
84 SkASSERT(mask->fFormat == SkMask::k3D_Format); |
|
85 |
|
86 int specular = light.fSpecular; |
|
87 int ambient = light.fAmbient; |
|
88 SkFixed lx = SkScalarToFixed(light.fDirection[0]); |
|
89 SkFixed ly = SkScalarToFixed(light.fDirection[1]); |
|
90 SkFixed lz = SkScalarToFixed(light.fDirection[2]); |
|
91 SkFixed lz_dot_nz = lz * kDelta; |
|
92 int lz_dot8 = lz >> 8; |
|
93 |
|
94 size_t planeSize = mask->computeImageSize(); |
|
95 uint8_t* alpha = mask->fImage; |
|
96 uint8_t* multiply = (uint8_t*)alpha + planeSize; |
|
97 uint8_t* additive = multiply + planeSize; |
|
98 |
|
99 int rowBytes = mask->fRowBytes; |
|
100 int maxy = mask->fBounds.height() - 1; |
|
101 int maxx = mask->fBounds.width() - 1; |
|
102 |
|
103 int prev_row = 0; |
|
104 for (int y = 0; y <= maxy; y++) { |
|
105 int next_row = neq_to_mask(y, maxy) & rowBytes; |
|
106 |
|
107 for (int x = 0; x <= maxx; x++) { |
|
108 if (alpha[x]) { |
|
109 int nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_one(x)]; |
|
110 int ny = alpha[x + next_row] - alpha[x - prev_row]; |
|
111 |
|
112 SkFixed numer = lx * nx + ly * ny + lz_dot_nz; |
|
113 int mul = ambient; |
|
114 int add = 0; |
|
115 |
|
116 if (numer > 0) { // preflight when numer/denom will be <= 0 |
|
117 #if 0 |
|
118 int denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta); |
|
119 SkFixed dot = numer / denom; |
|
120 dot >>= 8; // now dot is 2^8 instead of 2^16 |
|
121 #else |
|
122 // can use full numer, but then we need to call SkFixedMul, since |
|
123 // numer is 24 bits, and our table is 12 bits |
|
124 |
|
125 // SkFixed dot = SkFixedMul(numer, gTable[]) >> 8 |
|
126 SkFixed dot = (unsigned)(numer >> 4) * gInvSqrtTable[(SkAbs32(nx) >> 1 << 7) | (SkAbs32(ny) >> 1)] >> 20; |
|
127 #endif |
|
128 mul = SkFastMin32(mul + dot, 255); |
|
129 |
|
130 // now for the reflection |
|
131 |
|
132 // R = 2 (Light * Normal) Normal - Light |
|
133 // hilite = R * Eye(0, 0, 1) |
|
134 |
|
135 int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8; |
|
136 if (hilite > 0) { |
|
137 // pin hilite to 255, since our fast math is also a little sloppy |
|
138 hilite = SkClampMax(hilite, 255); |
|
139 |
|
140 // specular is 4.4 |
|
141 // would really like to compute the fractional part of this |
|
142 // and then possibly cache a 256 table for a given specular |
|
143 // value in the light, and just pass that in to this function. |
|
144 add = hilite; |
|
145 for (int i = specular >> 4; i > 0; --i) { |
|
146 add = div255(add * hilite); |
|
147 } |
|
148 } |
|
149 } |
|
150 multiply[x] = SkToU8(mul); |
|
151 additive[x] = SkToU8(add); |
|
152 |
|
153 // multiply[x] = 0xFF; |
|
154 // additive[x] = 0; |
|
155 // ((uint8_t*)alpha)[x] = alpha[x] * multiply[x] >> 8; |
|
156 } |
|
157 } |
|
158 alpha += rowBytes; |
|
159 multiply += rowBytes; |
|
160 additive += rowBytes; |
|
161 prev_row = rowBytes; |
|
162 } |
|
163 } |