Commit 986d3108ac9fd0d7344bc83b20ccd64d433a02b3

Anuj Verma 2020-08-19T12:56:58

[sdf] Add function to generate SDF. * src/sdf/ftsdf.c (sdf_generate): New function, currently disabled. This is a proof-of-concept implementation: It doesn't use any optimization, it simply checks all grid points against all contours.

diff --git a/ChangeLog b/ChangeLog
index bfe6afc..e5cb76d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2020-08-19  Anuj Verma  <anujv@iitbhilai.ac.in>
 
+	[sdf] Add function to generate SDF.
+
+	* src/sdf/ftsdf.c (sdf_generate): New function, currently disabled. 
+	This is a proof-of-concept implementation: It doesn't use any
+	optimization, it simply checks all grid points against all contours.
+
+2020-08-19  Anuj Verma  <anujv@iitbhilai.ac.in>
+
 	[sdf] Add functions to get shortest distance from any edge/contour.
 
 	* src/sdf/ftsdf.c (sdf_edge_get_min_distance): New function.
diff --git a/src/sdf/ftsdf.c b/src/sdf/ftsdf.c
index 5a83d8f..c17daff 100644
--- a/src/sdf/ftsdf.c
+++ b/src/sdf/ftsdf.c
@@ -2887,6 +2887,166 @@
     return error;
   }
 
-#endif
+
+  /**************************************************************************
+   *
+   * @Function:
+   *   sdf_generate
+   *
+   * @Description:
+   *   This is the main function that is responsible for generating signed
+   *   distance fields.  The function does not align or compute the size of
+   *   `bitmap`; therefore the calling application must set up `bitmap`
+   *   properly and transform the `shape' appropriately in advance.
+   *
+   *   Currently we check all pixels against all contours and all edges.
+   *
+   * @Input:
+   *   internal_params ::
+   *     Internal parameters and properties required by the rasterizer.  See
+   *     @SDF_Params for more.
+   *
+   *   shape ::
+   *     A complete shape which is used to generate SDF.
+   *
+   *   spread ::
+   *     Maximum distances to be allowed in the output bitmap.
+   *
+   * @Output:
+   *   bitmap ::
+   *     The output bitmap which will contain the SDF information.
+   *
+   * @Return:
+   *   FreeType error, 0 means success.
+   *
+   */
+  static FT_Error
+  sdf_generate( const SDF_Params  internal_params,
+                const SDF_Shape*  shape,
+                FT_UInt           spread,
+                const FT_Bitmap*  bitmap )
+  {
+    FT_Error  error = FT_Err_Ok;
+
+    FT_UInt  width = 0;
+    FT_UInt  rows  = 0;
+    FT_UInt  x     = 0;   /* used to loop in x direction, i.e., width     */
+    FT_UInt  y     = 0;   /* used to loop in y direction, i.e., rows      */
+    FT_UInt  sp_sq = 0;   /* `spread` [* `spread`] as a 16.16 fixed value */
+
+    FT_Short*  buffer;
+
+
+    if ( !shape || !bitmap )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    if ( spread < MIN_SPREAD || spread > MAX_SPREAD )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    width  = bitmap->width;
+    rows   = bitmap->rows;
+    buffer = (FT_Short*)bitmap->buffer;
+
+    if ( USE_SQUARED_DISTANCES )
+      sp_sq = FT_INT_16D16( spread * spread );
+    else
+      sp_sq = FT_INT_16D16( spread );
+
+    if ( width == 0 || rows == 0 )
+    {
+      FT_TRACE0(( "sdf_generate:"
+                  " Cannot render glyph with width/height == 0\n" ));
+      FT_TRACE0(( "             "
+                  " (width, height provided [%d, %d])\n",
+                  width, rows ));
+
+      error = FT_THROW( Cannot_Render_Glyph );
+      goto Exit;
+    }
+
+    /* loop over all rows */
+    for ( y = 0; y < rows; y++ )
+    {
+      /* loop over all pixels of a row */
+      for ( x = 0; x < width; x++ )
+      {
+        /* `grid_point` is the current pixel position; */
+        /* our task is to find the shortest distance   */
+        /* from this point to the entire shape.        */
+        FT_26D6_Vec          grid_point = zero_vector;
+        SDF_Signed_Distance  min_dist   = max_sdf;
+        SDF_Contour*         contour_list;
+
+        FT_UInt   index;
+        FT_Short  value;
+
+
+        grid_point.x = FT_INT_26D6( x );
+        grid_point.y = FT_INT_26D6( y );
+
+        /* This `grid_point' is at the corner, but we */
+        /* use the center of the pixel.               */
+        grid_point.x += FT_INT_26D6( 1 ) / 2;
+        grid_point.y += FT_INT_26D6( 1 ) / 2;
+
+        contour_list = shape->contours;
+
+        /* iterate over all contours manually */
+        while ( contour_list )
+        {
+          SDF_Signed_Distance  current_dist = max_sdf;
+
+
+          FT_CALL( sdf_contour_get_min_distance( contour_list,
+                                                 grid_point,
+                                                 &current_dist ) );
+
+          if ( current_dist.distance < min_dist.distance )
+            min_dist = current_dist;
+
+          contour_list = contour_list->next;
+        }
+
+        /* [OPTIMIZATION]: if (min_dist > sp_sq) then simply clamp  */
+        /*                 the value to spread to avoid square_root */
+
+        /* clamp the values to spread */
+        if ( min_dist.distance > sp_sq )
+          min_dist.distance = sp_sq;
+
+        /* square_root the values and fit in a 6.10 fixed point */
+        if ( USE_SQUARED_DISTANCES )
+          min_dist.distance = square_root( min_dist.distance );
+
+        if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT )
+          min_dist.sign = -min_dist.sign;
+        if ( internal_params.flip_sign )
+          min_dist.sign = -min_dist.sign;
+
+        min_dist.distance /= 64; /* convert from 16.16 to 22.10 */
+
+        value  = min_dist.distance & 0x0000FFFF; /* truncate to 6.10 */
+        value *= min_dist.sign;
+
+        if ( internal_params.flip_y )
+          index = y * width + x;
+        else
+          index = ( rows - y - 1 ) * width + x;
+
+        buffer[index] = value;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+#endif /* 0 */
 
 /* END */