[sdf] Added function to generate SDF.

* src/sdf/ftsdf.c (sdf_generate): Added function to generate SDF. This one doesn't use
  any optimization, it simply check all grid point against all contours.
This commit is contained in:
Anuj Verma 2020-08-19 12:56:58 +05:30
parent 75182d8ad1
commit 596bcfd340
1 changed files with 152 additions and 0 deletions

View File

@ -2647,6 +2647,158 @@
return error;
}
/**************************************************************************
*
* @Function:
* sdf_generate
*
* @Description:
* This is the main function that is responsible for generating
* signed distance fields. The function will not align or compute
* the size of the `bitmap', therefore setup the `bitmap' properly
* and transform the `shape' appropriately before calling this
* function.
* Currently we check all the pixels against all the contours and
* all the edges.
*
* @Input:
* internal_params ::
* Internal parameters and properties required by the rasterizer.
* See `SDF_Params' for the actual parameters.
*
* shape ::
* A complete shape which is used to generate SDF.
*
* spread ::
* Maximum distances to be allowed inthe output bitmap.
*
* @Return
* bitmap ::
* The output bitmap which will contain the SDF information.
*
* FT_Error ::
* 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' int 16.16 fixed */
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] sdf_generate:\n"
" Cannot render glyph with width/height == 0\n"
" (width, height provided [%d, %d])", width, rows ));
error = FT_THROW( Cannot_Render_Glyph );
goto Exit;
}
/* loop through all the rows */
for ( y = 0; y < rows; y++ )
{
/* loop through all the 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 through all the 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
/* END */