OLD | NEW |
| (Empty) |
1 /* libs/graphics/effects/SkEmbossMask.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkEmbossMask.h" | |
19 | |
20 static inline int nonzero_to_one(int x) | |
21 { | |
22 #if 0 | |
23 return x != 0; | |
24 #else | |
25 return ((unsigned)(x | -x)) >> 31; | |
26 #endif | |
27 } | |
28 | |
29 static inline int neq_to_one(int x, int max) | |
30 { | |
31 #if 0 | |
32 return x != max; | |
33 #else | |
34 SkASSERT(x >= 0 && x <= max); | |
35 return ((unsigned)(x - max)) >> 31; | |
36 #endif | |
37 } | |
38 | |
39 static inline int neq_to_mask(int x, int max) | |
40 { | |
41 #if 0 | |
42 return -(x != max); | |
43 #else | |
44 SkASSERT(x >= 0 && x <= max); | |
45 return (x - max) >> 31; | |
46 #endif | |
47 } | |
48 | |
49 static inline unsigned div255(unsigned x) | |
50 { | |
51 SkASSERT(x <= (255*255)); | |
52 return x * ((1 << 24) / 255) >> 24; | |
53 } | |
54 | |
55 #define kDelta 32 // small enough to show off angle differences | |
56 | |
57 #include "SkEmbossMask_Table.h" | |
58 | |
59 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG) | |
60 | |
61 #include <stdio.h> | |
62 | |
63 void SkEmbossMask_BuildTable() | |
64 { | |
65 // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fi
xed" table | |
66 | |
67 FILE* file = ::fopen("SkEmbossMask_Table.h", "w"); | |
68 SkASSERT(file); | |
69 ::fprintf(file, "#include \"SkTypes.h\"\n\n"); | |
70 ::fprintf(file, "static const U16 gInvSqrtTable[128 * 128] = {\n"); | |
71 for (int dx = 0; dx <= 255/2; dx++) | |
72 { | |
73 for (int dy = 0; dy <= 255/2; dy++) | |
74 { | |
75 if ((dy & 15) == 0) | |
76 ::fprintf(file, "\t"); | |
77 | |
78 uint16_t value = SkToU16((1 << 15) / SkSqrt32(dx * dx + dy * dy + kD
elta*kDelta/4)); | |
79 | |
80 ::fprintf(file, "0x%04X", value); | |
81 if (dx * 128 + dy < 128*128-1) | |
82 ::fprintf(file, ", "); | |
83 if ((dy & 15) == 15) | |
84 ::fprintf(file, "\n"); | |
85 } | |
86 } | |
87 ::fprintf(file, "};\n#define kDeltaUsedToBuildTable\t%d\n", kDelta); | |
88 ::fclose(file); | |
89 } | |
90 | |
91 #endif | |
92 | |
93 void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) | |
94 { | |
95 SkASSERT(kDelta == kDeltaUsedToBuildTable); | |
96 | |
97 SkASSERT(mask->fFormat == SkMask::k3D_Format); | |
98 | |
99 int specular = light.fSpecular; | |
100 int ambient = light.fAmbient; | |
101 SkFixed lx = SkScalarToFixed(light.fDirection[0]); | |
102 SkFixed ly = SkScalarToFixed(light.fDirection[1]); | |
103 SkFixed lz = SkScalarToFixed(light.fDirection[2]); | |
104 SkFixed lz_dot_nz = lz * kDelta; | |
105 int lz_dot8 = lz >> 8; | |
106 | |
107 size_t planeSize = mask->computeImageSize(); | |
108 uint8_t* alpha = mask->fImage; | |
109 uint8_t* multiply = (uint8_t*)alpha + planeSize; | |
110 uint8_t* additive = multiply + planeSize; | |
111 | |
112 int rowBytes = mask->fRowBytes; | |
113 int maxy = mask->fBounds.height() - 1; | |
114 int maxx = mask->fBounds.width() - 1; | |
115 | |
116 int prev_row = 0; | |
117 for (int y = 0; y <= maxy; y++) | |
118 { | |
119 int next_row = neq_to_mask(y, maxy) & rowBytes; | |
120 | |
121 for (int x = 0; x <= maxx; x++) | |
122 { | |
123 if (alpha[x]) | |
124 { | |
125 int nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_o
ne(x)]; | |
126 int ny = alpha[x + next_row] - alpha[x - prev_row]; | |
127 | |
128 SkFixed numer = lx * nx + ly * ny + lz_dot_nz; | |
129 int mul = ambient; | |
130 int add = 0; | |
131 | |
132 if (numer > 0) // preflight when numer/denom will be <= 0 | |
133 { | |
134 #if 0 | |
135 int denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta); | |
136 SkFixed dot = numer / denom; | |
137 dot >>= 8; // now dot is 2^8 instead of 2^16 | |
138 #else | |
139 // can use full numer, but then we need to call SkFixedMul,
since | |
140 // numer is 24 bits, and our table is 12 bits | |
141 | |
142 // SkFixed dot = SkFixedMul(numer, gTable[]) >> 8 | |
143 SkFixed dot = (unsigned)(numer >> 4) * gInvSqrtTable[(SkAbs3
2(nx) >> 1 << 7) | (SkAbs32(ny) >> 1)] >> 20; | |
144 #endif | |
145 mul = SkFastMin32(mul + dot, 255); | |
146 | |
147 // now for the reflection | |
148 | |
149 // R = 2 (Light * Normal) Normal - Light | |
150 // hilite = R * Eye(0, 0, 1) | |
151 | |
152 int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8; | |
153 if (hilite > 0) | |
154 { | |
155 // pin hilite to 255, since our fast math is also a litt
le sloppy | |
156 hilite = SkClampMax(hilite, 255); | |
157 | |
158 // specular is 4.4 | |
159 // would really like to compute the fractional part of t
his | |
160 // and then possibly cache a 256 table for a given specu
lar | |
161 // value in the light, and just pass that in to this fun
ction. | |
162 add = hilite; | |
163 for (int i = specular >> 4; i > 0; --i) | |
164 add = div255(add * hilite); | |
165 } | |
166 } | |
167 multiply[x] = SkToU8(mul); | |
168 additive[x] = SkToU8(add); | |
169 | |
170 // multiply[x] = 0xFF; | |
171 // additive[x] = 0; | |
172 // ((uint8_t*)alpha)[x] = alpha[x] * multiply[x] >> 8; | |
173 } | |
174 } | |
175 alpha += rowBytes; | |
176 multiply += rowBytes; | |
177 additive += rowBytes; | |
178 prev_row = rowBytes; | |
179 } | |
180 } | |
181 | |
182 | |
OLD | NEW |