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 +}