Home | History | Annotate | Download | only in effects
      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