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 "fixed" 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 + kDelta*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_one(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[(SkAbs32(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 little sloppy 156 hilite = SkClampMax(hilite, 255); 157 158 // specular is 4.4 159 // would really like to compute the fractional part of this 160 // and then possibly cache a 256 table for a given specular 161 // value in the light, and just pass that in to this function. 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 183