gfx/skia/trunk/src/effects/SkEmbossMask.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/effects/SkEmbossMask.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,163 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkEmbossMask.h"
    1.14 +#include "SkMath.h"
    1.15 +
    1.16 +static inline int nonzero_to_one(int x) {
    1.17 +#if 0
    1.18 +    return x != 0;
    1.19 +#else
    1.20 +    return ((unsigned)(x | -x)) >> 31;
    1.21 +#endif
    1.22 +}
    1.23 +
    1.24 +static inline int neq_to_one(int x, int max) {
    1.25 +#if 0
    1.26 +    return x != max;
    1.27 +#else
    1.28 +    SkASSERT(x >= 0 && x <= max);
    1.29 +    return ((unsigned)(x - max)) >> 31;
    1.30 +#endif
    1.31 +}
    1.32 +
    1.33 +static inline int neq_to_mask(int x, int max) {
    1.34 +#if 0
    1.35 +    return -(x != max);
    1.36 +#else
    1.37 +    SkASSERT(x >= 0 && x <= max);
    1.38 +    return (x - max) >> 31;
    1.39 +#endif
    1.40 +}
    1.41 +
    1.42 +static inline unsigned div255(unsigned x) {
    1.43 +    SkASSERT(x <= (255*255));
    1.44 +    return x * ((1 << 24) / 255) >> 24;
    1.45 +}
    1.46 +
    1.47 +#define kDelta  32  // small enough to show off angle differences
    1.48 +
    1.49 +#include "SkEmbossMask_Table.h"
    1.50 +
    1.51 +#if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
    1.52 +
    1.53 +#include <stdio.h>
    1.54 +
    1.55 +void SkEmbossMask_BuildTable() {
    1.56 +    // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
    1.57 +
    1.58 +    FILE* file = ::fopen("SkEmbossMask_Table.h", "w");
    1.59 +    SkASSERT(file);
    1.60 +    ::fprintf(file, "#include \"SkTypes.h\"\n\n");
    1.61 +    ::fprintf(file, "static const U16 gInvSqrtTable[128 * 128] = {\n");
    1.62 +    for (int dx = 0; dx <= 255/2; dx++) {
    1.63 +        for (int dy = 0; dy <= 255/2; dy++) {
    1.64 +            if ((dy & 15) == 0)
    1.65 +                ::fprintf(file, "\t");
    1.66 +
    1.67 +            uint16_t value = SkToU16((1 << 15) / SkSqrt32(dx * dx + dy * dy + kDelta*kDelta/4));
    1.68 +
    1.69 +            ::fprintf(file, "0x%04X", value);
    1.70 +            if (dx * 128 + dy < 128*128-1) {
    1.71 +                ::fprintf(file, ", ");
    1.72 +            }
    1.73 +            if ((dy & 15) == 15) {
    1.74 +                ::fprintf(file, "\n");
    1.75 +            }
    1.76 +        }
    1.77 +    }
    1.78 +    ::fprintf(file, "};\n#define kDeltaUsedToBuildTable\t%d\n", kDelta);
    1.79 +    ::fclose(file);
    1.80 +}
    1.81 +
    1.82 +#endif
    1.83 +
    1.84 +void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) {
    1.85 +    SkASSERT(kDelta == kDeltaUsedToBuildTable);
    1.86 +
    1.87 +    SkASSERT(mask->fFormat == SkMask::k3D_Format);
    1.88 +
    1.89 +    int     specular = light.fSpecular;
    1.90 +    int     ambient = light.fAmbient;
    1.91 +    SkFixed lx = SkScalarToFixed(light.fDirection[0]);
    1.92 +    SkFixed ly = SkScalarToFixed(light.fDirection[1]);
    1.93 +    SkFixed lz = SkScalarToFixed(light.fDirection[2]);
    1.94 +    SkFixed lz_dot_nz = lz * kDelta;
    1.95 +    int     lz_dot8 = lz >> 8;
    1.96 +
    1.97 +    size_t      planeSize = mask->computeImageSize();
    1.98 +    uint8_t*    alpha = mask->fImage;
    1.99 +    uint8_t*    multiply = (uint8_t*)alpha + planeSize;
   1.100 +    uint8_t*    additive = multiply + planeSize;
   1.101 +
   1.102 +    int rowBytes = mask->fRowBytes;
   1.103 +    int maxy = mask->fBounds.height() - 1;
   1.104 +    int maxx = mask->fBounds.width() - 1;
   1.105 +
   1.106 +    int prev_row = 0;
   1.107 +    for (int y = 0; y <= maxy; y++) {
   1.108 +        int next_row = neq_to_mask(y, maxy) & rowBytes;
   1.109 +
   1.110 +        for (int x = 0; x <= maxx; x++) {
   1.111 +            if (alpha[x]) {
   1.112 +                int nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_one(x)];
   1.113 +                int ny = alpha[x + next_row] - alpha[x - prev_row];
   1.114 +
   1.115 +                SkFixed numer = lx * nx + ly * ny + lz_dot_nz;
   1.116 +                int     mul = ambient;
   1.117 +                int     add = 0;
   1.118 +
   1.119 +                if (numer > 0) {  // preflight when numer/denom will be <= 0
   1.120 +#if 0
   1.121 +                    int denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta);
   1.122 +                    SkFixed dot = numer / denom;
   1.123 +                    dot >>= 8;  // now dot is 2^8 instead of 2^16
   1.124 +#else
   1.125 +                    // can use full numer, but then we need to call SkFixedMul, since
   1.126 +                    // numer is 24 bits, and our table is 12 bits
   1.127 +
   1.128 +                    // SkFixed dot = SkFixedMul(numer, gTable[]) >> 8
   1.129 +                    SkFixed dot = (unsigned)(numer >> 4) * gInvSqrtTable[(SkAbs32(nx) >> 1 << 7) | (SkAbs32(ny) >> 1)] >> 20;
   1.130 +#endif
   1.131 +                    mul = SkFastMin32(mul + dot, 255);
   1.132 +
   1.133 +                    // now for the reflection
   1.134 +
   1.135 +                    //  R = 2 (Light * Normal) Normal - Light
   1.136 +                    //  hilite = R * Eye(0, 0, 1)
   1.137 +
   1.138 +                    int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8;
   1.139 +                    if (hilite > 0) {
   1.140 +                        // pin hilite to 255, since our fast math is also a little sloppy
   1.141 +                        hilite = SkClampMax(hilite, 255);
   1.142 +
   1.143 +                        // specular is 4.4
   1.144 +                        // would really like to compute the fractional part of this
   1.145 +                        // and then possibly cache a 256 table for a given specular
   1.146 +                        // value in the light, and just pass that in to this function.
   1.147 +                        add = hilite;
   1.148 +                        for (int i = specular >> 4; i > 0; --i) {
   1.149 +                            add = div255(add * hilite);
   1.150 +                        }
   1.151 +                    }
   1.152 +                }
   1.153 +                multiply[x] = SkToU8(mul);
   1.154 +                additive[x] = SkToU8(add);
   1.155 +
   1.156 +            //  multiply[x] = 0xFF;
   1.157 +            //  additive[x] = 0;
   1.158 +            //  ((uint8_t*)alpha)[x] = alpha[x] * multiply[x] >> 8;
   1.159 +            }
   1.160 +        }
   1.161 +        alpha += rowBytes;
   1.162 +        multiply += rowBytes;
   1.163 +        additive += rowBytes;
   1.164 +        prev_row = rowBytes;
   1.165 +    }
   1.166 +}

mercurial