summaryrefslogtreecommitdiff
path: root/src/sdf/ftsdfcommon.h
blob: 7ce49bb980c96e6ceb8a9c7fbbc6281c97913895 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/****************************************************************************
 *
 * ftsdfcommon.h
 *
 *   Auxiliary data for Signed Distance Field support (specification only).
 *
 * Copyright (C) 2020-2021 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * Written by Anuj Verma.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */


  /****************************************************
   *
   * This file contains common functions and properties
   * for both the 'sdf' and 'bsdf' renderers.
   *
   */

#ifndef FTSDFCOMMON_H_
#define FTSDFCOMMON_H_

#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/freetype.h>


FT_BEGIN_HEADER


  /**************************************************************************
   *
   * default values (cannot be set individually for each renderer)
   *
   */

  /* default spread value */
#define DEFAULT_SPREAD  8
  /* minimum spread supported by the renderer */
#define MIN_SPREAD      2
  /* maximum spread supported by the renderer */
#define MAX_SPREAD      32


  /**************************************************************************
   *
   * common definitions (cannot be set individually for each renderer)
   *
   */

  /* If this macro is set to 1 the rasterizer uses squared distances for */
  /* computation.  It can greatly improve the performance but there is a */
  /* chance of overflow and artifacts.  You can safely use it up to a    */
  /* pixel size of 128.                                                  */
#ifndef USE_SQUARED_DISTANCES
#define USE_SQUARED_DISTANCES  0
#endif


  /**************************************************************************
   *
   * common macros
   *
   */

  /* convert int to 26.6 fixed-point   */
#define FT_INT_26D6( x )   ( x * 64 )
  /* convert int to 16.16 fixed-point  */
#define FT_INT_16D16( x )  ( x * 65536 )
  /* convert 26.6 to 16.16 fixed-point */
#define FT_26D6_16D16( x ) ( x * 1024 )


  /* Convenience macro to call a function; it  */
  /* jumps to label `Exit` if an error occurs. */
#define FT_CALL( x ) do                          \
                     {                           \
                       error = ( x );            \
                       if ( error != FT_Err_Ok ) \
                         goto Exit;              \
                     } while ( 0 )


  /*
   * The macro `VECTOR_LENGTH_16D16` computes either squared distances or
   * actual distances, depending on the value of `USE_SQUARED_DISTANCES`.
   *
   * By using squared distances the performance can be greatly improved but
   * there is a risk of overflow.
   */
#if USE_SQUARED_DISTANCES
#define VECTOR_LENGTH_16D16( v )  ( FT_MulFix( v.x, v.x ) + \
                                    FT_MulFix( v.y, v.y ) )
#else
#define VECTOR_LENGTH_16D16( v )  FT_Vector_Length( &v )
#endif


  /**************************************************************************
   *
   * common typedefs
   *
   */

  typedef FT_Vector FT_26D6_Vec;   /* with 26.6 fixed-point components  */
  typedef FT_Vector FT_16D16_Vec;  /* with 16.16 fixed-point components */

  typedef FT_Fixed  FT_16D16;      /* 16.16 fixed-point representation  */
  typedef FT_Fixed  FT_26D6;       /* 26.6 fixed-point representation   */
  typedef FT_Byte   FT_SDFFormat;  /* format to represent SDF data      */

  typedef FT_BBox   FT_CBox;       /* control box of a curve            */


  /**************************************************************************
   *
   * common functions
   *
   */

  /*
   * Original algorithm:
   *
   *   https://github.com/chmike/fpsqrt
   *
   * Use this to compute the square root of a 16.16 fixed point number.
   */
  static FT_16D16
  square_root( FT_16D16  val )
  {
    FT_ULong  t, q, b, r;


    r = (FT_ULong)val;
    b = 0x40000000L;
    q = 0;

    while ( b > 0x40L )
    {
      t = q + b;

      if ( r >= t )
      {
        r -= t;
        q  = t + b;
      }

      r <<= 1;
      b >>= 1;
    }

    q >>= 8;

    return (FT_16D16)q;
  }

  /**************************************************************************
   *
   * format and sign manipulating functions
   *
   */

  /*
   * Convert 16.16 fixed point value to the desired output format.
   * In this case we reduce 16.16 fixed point value to normalized
   * 8-bit values.
   * The `max_value` in the parameter is the maximum value in the
   * distance field map and is equal to the spread.  We normalize
   * the distances using this value instead of computing the maximum
   * value for the entire bitmap.
   * You can use this function to map the 16.16 signed values to any
   * format required. Do note that the output buffer is 8-bit, so only
   * use 8-bit format for `FT_SDFFormat`, or increase buffer size in
   * `ftsdfrend.c`.
   */
  static FT_SDFFormat
  map_fixed_to_sdf( FT_16D16 dist, FT_16D16 max_value )
  {
    FT_SDFFormat out;
    FT_16D16     udist;


    /* normalize the distance values */
    dist = FT_DivFix( dist, max_value );

    udist = dist < 0 ? -dist : dist;

    /* Reduce the distance values to 8 bits, +1/-1 in   */
    /* 16.16 takes the 16th bit.  So we right shift the */
    /* number by 9 to make it fit in the 7 bit range.   */
    /* 1 bit is reserved for the sign.                  */
    udist >>= 9;

    /* Since char can only store max positive value */
    /* of 127 we need to make sure it does not wrap */
    /* around and give a negative value.            */
    if ( dist > 0 && udist > 127 )
      udist = 127;
    if ( dist < 0 && udist > 128 )
      udist = 128;

    /* Output the data; negative values are from [0, 127] and positive    */
    /* from [128, 255].  One important thing is that negative values      */
    /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */
    /* More on that in `freetype.h` near `FT_RENDER_MODE_SDF`             */
    out = dist < 0 ? 128 - (FT_SDFFormat)udist :
                     (FT_SDFFormat)udist + 128;
    return out;
  }

  /*
   * Invert the signed distance packed into the corresponding format.
   * So if the values are negative they will become positive in the
   * chosen format.
   *
   * [Note]: This function should only be used after converting the
   *         16.16 signed distance values to `FT_SDFFormat`, if that
   *         conversion has not been done, then simply invert the sign
   *         and use the above function to pack the values.
   */
  static FT_SDFFormat
  invert_sign( FT_SDFFormat dist ) {
    return 255 - dist;
  }


FT_END_HEADER

#endif /* FTSDFCOMMON_H_ */


/* END */