1 /**************************************************************************** 2 * 3 * ftsdfcommon.c 4 * 5 * Auxiliary data for Signed Distance Field support (body). 6 * 7 * Copyright (C) 2020-2023 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * Written by Anuj Verma. 11 * 12 * This file is part of the FreeType project, and may only be used, 13 * modified, and distributed under the terms of the FreeType project 14 * license, LICENSE.TXT. By continuing to use, modify, or distribute 15 * this file you indicate that you have read the license and 16 * understand and accept it fully. 17 * 18 */ 19 20 21 #include "ftsdf.h" 22 #include "ftsdfcommon.h" 23 24 25 /************************************************************************** 26 * 27 * common functions 28 * 29 */ 30 31 /* 32 * Original algorithm: 33 * 34 * https://github.com/chmike/fpsqrt 35 * 36 * Use this to compute the square root of a 16.16 fixed-point number. 37 */ 38 FT_LOCAL_DEF( FT_16D16 ) square_root(FT_16D16 val)39 square_root( FT_16D16 val ) 40 { 41 FT_ULong t, q, b, r; 42 43 44 r = (FT_ULong)val; 45 b = 0x40000000L; 46 q = 0; 47 48 while ( b > 0x40L ) 49 { 50 t = q + b; 51 52 if ( r >= t ) 53 { 54 r -= t; 55 q = t + b; 56 } 57 58 r <<= 1; 59 b >>= 1; 60 } 61 62 q >>= 8; 63 64 return (FT_16D16)q; 65 } 66 67 68 /************************************************************************** 69 * 70 * format and sign manipulating functions 71 * 72 */ 73 74 /* 75 * Convert 16.16 fixed-point values to the desired output format. 76 * In this case we reduce 16.16 fixed-point values to normalized 77 * 8-bit values. 78 * 79 * The `max_value` in the parameter is the maximum value in the 80 * distance field map and is equal to the spread. We normalize 81 * the distances using this value instead of computing the maximum 82 * value for the entire bitmap. 83 * 84 * You can use this function to map the 16.16 signed values to any 85 * format required. Do note that the output buffer is 8-bit, so only 86 * use an 8-bit format for `FT_SDFFormat`, or increase the buffer size in 87 * `ftsdfrend.c`. 88 */ 89 FT_LOCAL_DEF( FT_SDFFormat ) map_fixed_to_sdf(FT_16D16 dist,FT_16D16 max_value)90 map_fixed_to_sdf( FT_16D16 dist, 91 FT_16D16 max_value ) 92 { 93 FT_SDFFormat out; 94 FT_16D16 udist; 95 96 97 /* normalize the distance values */ 98 dist = FT_DivFix( dist, max_value ); 99 100 udist = dist < 0 ? -dist : dist; 101 102 /* Reduce the distance values to 8 bits. */ 103 /* */ 104 /* Since +1/-1 in 16.16 takes the 16th bit, we right-shift */ 105 /* the number by 9 to make it fit into the 7-bit range. */ 106 /* */ 107 /* One bit is reserved for the sign. */ 108 udist >>= 9; 109 110 /* Since `char` can only store a maximum positive value */ 111 /* of 127 we need to make sure it does not wrap around and */ 112 /* give a negative value. */ 113 if ( dist > 0 && udist > 127 ) 114 udist = 127; 115 if ( dist < 0 && udist > 128 ) 116 udist = 128; 117 118 /* Output the data; negative values are from [0, 127] and positive */ 119 /* from [128, 255]. One important thing is that negative values */ 120 /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */ 121 /* More on that in `freetype.h` near the documentation of */ 122 /* `FT_RENDER_MODE_SDF`. */ 123 out = dist < 0 ? 128 - (FT_SDFFormat)udist 124 : (FT_SDFFormat)udist + 128; 125 126 return out; 127 } 128 129 130 /* 131 * Invert the signed distance packed into the corresponding format. 132 * So if the values are negative they will become positive in the 133 * chosen format. 134 * 135 * [Note]: This function should only be used after converting the 136 * 16.16 signed distance values to `FT_SDFFormat`. If that 137 * conversion has not been done, then simply invert the sign 138 * and use the above function to pack the values. 139 */ 140 FT_LOCAL_DEF( FT_SDFFormat ) invert_sign(FT_SDFFormat dist)141 invert_sign( FT_SDFFormat dist ) 142 { 143 return 255 - dist; 144 } 145 146 147 /* END */ 148