[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.
This commit is contained in:
Anuj Verma 2020-08-19 12:56:58 +05:30 committed by Werner Lemberg
parent 0d52f4ae0a
commit 986d3108ac
2 changed files with 169 additions and 1 deletions

View File

@ -1,3 +1,11 @@
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.

View File

@ -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 */