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 )
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 )
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 )
141 invert_sign( FT_SDFFormat dist )
142 {
143 return 255 - dist;
144 }
145
146
147/* END */
148