[sdf] Added overlap support (currently only for TrueType).
* src/sdf/ftsdfrend.h (SDF_Renderer_Module): Removed the expermental `optimization' property. Added another property `overlaps', which can be used to turn on the overlap support. * src/sdf/ftsdf.h (SDF_Raster_Params): Ditto as above. * src/sdf/ftsdfrend.c (*): Added functionality to set and get the new `overlaps' property. * src/sdf/ftsdf.c (sdf_raster_render): Removed support for all the optimization modes and only keep the subdivision optimization and the new overlap support function. * src/sdf/ftsdf.c (sdf_generate_coarse_grid): Turned off until we can find a way to make it faster. * src/sdf/ftsdf.c (sdf_generate_with_overlaps): Added a function to generate SDF for shapes with overlapping contours. It basically generate SDF for separate contours in seperate bitmaps and then combine them to remove overlaps.
This commit is contained in:
parent
307b0cbd6f
commit
f644a47aae
|
@ -1,3 +1,31 @@
|
|||
2020-08-12 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||
|
||||
[sdf] Added overlap support (currently only for TrueType).
|
||||
|
||||
* src/sdf/ftsdfrend.h (SDF_Renderer_Module): Removed the
|
||||
expermental `optimization' property.
|
||||
Added another property `overlaps', which can be used to
|
||||
turn on the overlap support.
|
||||
|
||||
* src/sdf/ftsdf.h (SDF_Raster_Params): Ditto as above.
|
||||
|
||||
* src/sdf/ftsdfrend.c (*): Added functionality to set
|
||||
and get the new `overlaps' property.
|
||||
|
||||
* src/sdf/ftsdf.c (sdf_raster_render):
|
||||
Removed support for all the optimization modes and
|
||||
only keep the subdivision optimization and the new
|
||||
overlap support function.
|
||||
|
||||
* src/sdf/ftsdf.c (sdf_generate_coarse_grid): Turned
|
||||
off until we can find a way to make it faster.
|
||||
|
||||
* src/sdf/ftsdf.c (sdf_generate_with_overlaps): Added
|
||||
a function to generate SDF for shapes with overlapping
|
||||
contours. It basically generate SDF for separate contours
|
||||
in seperate bitmaps and then combine them to remove
|
||||
overlaps.
|
||||
|
||||
2020-08-7 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||
|
||||
[sdf, bsdf] Added better documentation.
|
||||
|
|
225
src/sdf/ftsdf.c
225
src/sdf/ftsdf.c
|
@ -143,10 +143,14 @@
|
|||
/* then they will be checked for corner if they have ambiguity. */
|
||||
#define CORNER_CHECK_EPSILON 32
|
||||
|
||||
#if 0
|
||||
|
||||
/* Coarse grid dimension. Probably will be removed in the future cause */
|
||||
/* coarse grid optimization is the slowest. */
|
||||
#define CG_DIMEN 8
|
||||
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* macros
|
||||
|
@ -247,8 +251,8 @@
|
|||
typedef enum SDF_Contour_Orientation_
|
||||
{
|
||||
SDF_ORIENTATION_NONE = 0,
|
||||
SDF_ORIENTATION_CW = 0,
|
||||
SDF_ORIENTATION_ACW = 0
|
||||
SDF_ORIENTATION_CW = 1,
|
||||
SDF_ORIENTATION_ACW = 2
|
||||
|
||||
} SDF_Contour_Orientation;
|
||||
|
||||
|
@ -410,6 +414,12 @@
|
|||
* useful because OpenGL and DirectX have different coordinate
|
||||
* system for textures.
|
||||
*
|
||||
* overload_sign ::
|
||||
* In the subdivision and bounding box optimization, the default
|
||||
* outside sign is taken as -1. This parameter can be used to
|
||||
* modify that behaviour. For example, while generating SDF for
|
||||
* single counter-clockwise contour the outside sign should be 1.
|
||||
*
|
||||
*/
|
||||
typedef struct SDF_Params_
|
||||
{
|
||||
|
@ -417,6 +427,8 @@
|
|||
FT_Bool flip_sign;
|
||||
FT_Bool flip_y;
|
||||
|
||||
FT_Int overload_sign;
|
||||
|
||||
} SDF_Params;
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -3068,6 +3080,9 @@
|
|||
FT_Char current_sign = -1;
|
||||
FT_UInt index;
|
||||
|
||||
if ( internal_params.overload_sign != 0 )
|
||||
current_sign = internal_params.overload_sign < 0 ? -1 : 1;
|
||||
|
||||
for ( i = 0; i < width; i++ )
|
||||
{
|
||||
index = j * width + i;
|
||||
|
@ -3145,6 +3160,186 @@
|
|||
return error;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
* sdf_generate_with_overlaps
|
||||
*
|
||||
* @Description:
|
||||
* This function can be used to generate SDF for glyphs with
|
||||
* overlapping contours. The function generate SDF for contours
|
||||
* seperately on seperate bitmaps (to generate SDF it uses
|
||||
* `sdf_generate_subdivision'). And at the end it simply combine
|
||||
* all the SDF into the output bitmap, this fixes all the signs
|
||||
* and removes overlaps.
|
||||
*
|
||||
* @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_with_overlaps( SDF_Params internal_params,
|
||||
SDF_Shape* shape,
|
||||
FT_UInt spread,
|
||||
const FT_Bitmap* bitmap )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_Int num_contours; /* total number of contours */
|
||||
FT_Int i, j; /* iterators */
|
||||
FT_Bitmap* bitmaps; /* seperate bitmaps for contours */
|
||||
SDF_Contour* contour; /* temporary variable to iterate */
|
||||
SDF_Shape temp_shape; /* temporary shape */
|
||||
SDF_Contour* temp_contour; /* temporary contour */
|
||||
FT_Memory memory; /* to allocate memory */
|
||||
FT_6D10* t; /* target bitmap buffer */
|
||||
|
||||
/* orientation of all the seperate contours */
|
||||
SDF_Contour_Orientation* orientations;
|
||||
|
||||
|
||||
if ( !shape || !bitmap || !shape->memory )
|
||||
{
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* assign the necessary variables */
|
||||
contour = shape->contours;
|
||||
memory = shape->memory;
|
||||
temp_shape.memory = memory;
|
||||
num_contours = 0;
|
||||
|
||||
/* find the number of contours in the shape */
|
||||
while ( contour )
|
||||
{
|
||||
num_contours++;
|
||||
contour = contour->next;
|
||||
}
|
||||
|
||||
/* allocate the bitmaps to generate SDF for seperate contours */
|
||||
if ( SDF_ALLOC( bitmaps, num_contours * sizeof( *bitmaps ) ) )
|
||||
goto Exit;
|
||||
|
||||
/* allocate array to hold orientation for all contours */
|
||||
if ( SDF_ALLOC( orientations, num_contours * sizeof( *orientations ) ) )
|
||||
goto Exit;
|
||||
|
||||
contour = shape->contours;
|
||||
|
||||
/* Iterate through all the contours */
|
||||
/* and generate SDF seperately. */
|
||||
for ( i = 0; i < num_contours; i++ )
|
||||
{
|
||||
/* initialize the corresponding bitmap */
|
||||
FT_Bitmap_Init( &bitmaps[i] );
|
||||
|
||||
bitmaps[i].width = bitmap->width;
|
||||
bitmaps[i].rows = bitmap->rows;
|
||||
bitmaps[i].pitch = bitmap->pitch;
|
||||
bitmaps[i].num_grays = bitmap->num_grays;
|
||||
bitmaps[i].pixel_mode = bitmap->pixel_mode;
|
||||
|
||||
/* allocate memory for the buffer */
|
||||
if ( SDF_ALLOC( bitmaps[i].buffer, bitmap->rows * bitmap->pitch ) )
|
||||
goto Exit;
|
||||
|
||||
/* Allocate a temporary contour to pass to the */
|
||||
/* generation function. This is done because */
|
||||
/* `split_sdf_shape' deallocate the contour, */
|
||||
/* so we cannot pass a static memory. */
|
||||
if ( SDF_ALLOC( temp_contour, sizeof( *temp_contour ) ) )
|
||||
goto Exit;
|
||||
|
||||
/* initialize the new contour */
|
||||
temp_contour->edges = contour->edges;
|
||||
temp_contour->next = NULL;
|
||||
|
||||
/* Use the `temp_shape' to hold the new contour. */
|
||||
/* Now, the `temp_shape' has only one contour. */
|
||||
temp_shape.contours = temp_contour;
|
||||
|
||||
/* determine the orientation */
|
||||
orientations[i] = get_contour_orientation( temp_contour );
|
||||
|
||||
/* The `overload_sign; property is specific to */
|
||||
/* sdf_generate_bounding_box. This basically */
|
||||
/* overload the default sign of the outside */
|
||||
/* pixels. Which is necessary for counter clock */
|
||||
/* wise contours. */
|
||||
if ( orientations[i] == SDF_ORIENTATION_ACW )
|
||||
internal_params.overload_sign = -1;
|
||||
else
|
||||
internal_params.overload_sign = 0;
|
||||
|
||||
/* finally generate the SDF */
|
||||
FT_CALL( sdf_generate_subdivision( internal_params,
|
||||
&temp_shape,
|
||||
spread,
|
||||
&bitmaps[i] ) );
|
||||
|
||||
contour = contour->next;
|
||||
}
|
||||
|
||||
/* cast the output bitmap buffer */
|
||||
t = (FT_6D10*)bitmap->buffer;
|
||||
|
||||
/* Iterate through all the pixels and combine all the */
|
||||
/* seperate contours. This is the rule for combining: */
|
||||
/* */
|
||||
/* => For all clockwise contours compute the largest */
|
||||
/* value. Name this as `val_c'. */
|
||||
/* => For all counter clockwise contours compute the */
|
||||
/* smallest value. Name this as `val_ac'. */
|
||||
/* => Now, finally use the smaller of `val_c' and */
|
||||
/* `val_ac'. */
|
||||
for ( j = 0; j < bitmap->rows; j++ )
|
||||
{
|
||||
for ( i = 0; i < bitmap->width; i++ )
|
||||
{
|
||||
FT_Int id = j * bitmap->width + i; /* index of current pixel */
|
||||
FT_Int c; /* contour iterator */
|
||||
FT_6D10 val_c = SHRT_MIN; /* max clockwise value */
|
||||
FT_6D10 val_ac = SHRT_MAX; /* min anti-clockwise value */
|
||||
|
||||
|
||||
/* iterate through all the contours */
|
||||
for ( c = 0; c < num_contours; c++ )
|
||||
{
|
||||
/* current contour value */
|
||||
FT_6D10 temp = ((FT_6D10*)bitmaps[c].buffer)[id];
|
||||
|
||||
|
||||
if ( orientations[c] == SDF_ORIENTATION_CW )
|
||||
val_c = FT_MAX( val_c, temp ); /* for clockwise */
|
||||
else
|
||||
val_ac = FT_MIN( val_ac, temp ); /* for anti-clockwise */
|
||||
}
|
||||
|
||||
/* finally find the smaller of two and assign to output */
|
||||
t[id] = FT_MIN( val_c, val_ac );
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if 0 /* coarse grid optimization is the slowest at the moment. */
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
|
@ -3404,6 +3599,8 @@
|
|||
return error;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* interface functions
|
||||
|
@ -3526,6 +3723,7 @@
|
|||
internal_params.orientation = FT_Outline_Get_Orientation( outline );
|
||||
internal_params.flip_sign = sdf_params->flip_sign;
|
||||
internal_params.flip_y = sdf_params->flip_y;
|
||||
internal_params.overload_sign = 0;
|
||||
|
||||
/* assign a custom user pointer to `FT_Memory' */
|
||||
/* also keep a reference of the old user pointer */
|
||||
|
@ -3537,26 +3735,17 @@
|
|||
|
||||
FT_CALL( sdf_outline_decompose( outline, shape ) );
|
||||
|
||||
/* TEMPORARY */
|
||||
if ( sdf_params->optimization == OPTIMIZATION_BB )
|
||||
FT_CALL( sdf_generate_bounding_box( internal_params,
|
||||
shape, sdf_params->spread,
|
||||
sdf_params->root.target ) );
|
||||
else if ( sdf_params->optimization == OPTIMIZATION_SUB )
|
||||
if ( sdf_params->overlaps )
|
||||
FT_CALL( sdf_generate_with_overlaps( internal_params,
|
||||
shape, sdf_params->spread,
|
||||
sdf_params->root.target ) );
|
||||
else
|
||||
FT_CALL( sdf_generate_subdivision( internal_params,
|
||||
shape, sdf_params->spread,
|
||||
sdf_params->root.target ) );
|
||||
else if ( sdf_params->optimization == OPTIMIZATION_CG )
|
||||
FT_CALL( sdf_generate_coarse_grid( internal_params,
|
||||
shape, sdf_params->spread,
|
||||
sdf_params->root.target ) );
|
||||
else
|
||||
FT_CALL( sdf_generate( internal_params,
|
||||
shape, sdf_params->spread,
|
||||
sdf_params->root.target ) );
|
||||
|
||||
if ( shape )
|
||||
sdf_shape_done( &shape );
|
||||
//if ( shape )
|
||||
// sdf_shape_done( &shape );
|
||||
|
||||
/* restore the memory->user */
|
||||
SDF_MEMORY_TRACKER_DONE();
|
||||
|
|
|
@ -11,16 +11,6 @@
|
|||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
/* @experimental struct: */
|
||||
typedef enum Optimizations_ {
|
||||
OPTIMIZATION_NONE = 0, /* default: check all points against all edges */
|
||||
OPTIMIZATION_BB = 1, /* use bounding box to check nearby grid points */
|
||||
OPTIMIZATION_SUB = 2, /* subdivide then use bounding box */
|
||||
OPTIMIZATION_CG = 3 /* use coarse grid to only check relevant edges */
|
||||
|
||||
} Optimizations;
|
||||
/* --------- */
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @struct:
|
||||
|
@ -53,6 +43,13 @@ FT_BEGIN_HEADER
|
|||
* Setting this parameter to true maked the output image flipped
|
||||
* along the y-axis.
|
||||
*
|
||||
* overlaps ::
|
||||
* Set this to true to generate SDF for glyphs having overlapping
|
||||
* contours. The overlapping support is limited to glyph which do
|
||||
* not have self intersecting contours. Also, removing overlaps
|
||||
* require a considerable amount of extra memory and this is not
|
||||
* valid while generating SDF from bitmap.
|
||||
*
|
||||
* @note:
|
||||
* It is valid for both `sdf' and `bsdf' renderer.
|
||||
*
|
||||
|
@ -63,9 +60,7 @@ FT_BEGIN_HEADER
|
|||
FT_UInt spread;
|
||||
FT_Bool flip_sign;
|
||||
FT_Bool flip_y;
|
||||
|
||||
/* @experimental fields: */
|
||||
FT_Int optimization;
|
||||
FT_Bool overlaps;
|
||||
|
||||
} SDF_Raster_Params;
|
||||
|
||||
|
|
|
@ -81,15 +81,14 @@
|
|||
FT_TRACE7(( "[sdf] sdf_property_set: "
|
||||
"updated property `flip_y' to %d\n", val ));
|
||||
}
|
||||
/* TEMPORARY */
|
||||
else if ( ft_strcmp( property_name, "optimization" ) == 0 )
|
||||
else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
|
||||
{
|
||||
FT_Int val = *(const FT_Int*)value;
|
||||
|
||||
|
||||
render->optimization = val;
|
||||
render->overlaps = val;
|
||||
FT_TRACE7(( "[sdf] sdf_property_set: "
|
||||
"updated property `optimization' to %d\n", val ));
|
||||
"updated property `overlaps' to %d\n", val ));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -133,6 +132,13 @@
|
|||
|
||||
*val = render->flip_y;
|
||||
}
|
||||
else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
|
||||
{
|
||||
FT_Int* val = (FT_Int*)value;
|
||||
|
||||
|
||||
*val = render->overlaps;
|
||||
}
|
||||
else
|
||||
{
|
||||
FT_TRACE0(( "[sdf] sdf_property_get: "
|
||||
|
@ -179,9 +185,7 @@
|
|||
sdf_render->spread = DEFAULT_SPREAD;
|
||||
sdf_render->flip_sign = 0;
|
||||
sdf_render->flip_y = 0;
|
||||
|
||||
/* TEMPORARY */
|
||||
sdf_render->optimization = OPTIMIZATION_NONE;
|
||||
sdf_render->overlaps = 0;
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
@ -295,9 +299,7 @@
|
|||
params.spread = sdf_module->spread;
|
||||
params.flip_sign = sdf_module->flip_sign;
|
||||
params.flip_y = sdf_module->flip_y;
|
||||
|
||||
/* TEMPORARY */
|
||||
params.optimization = sdf_module->optimization;
|
||||
params.overlaps = sdf_module->overlaps;
|
||||
|
||||
/* render the outline */
|
||||
error = render->raster_render( render->raster, (const FT_Raster_Params*)¶ms );
|
||||
|
|
|
@ -40,9 +40,17 @@ FT_BEGIN_HEADER
|
|||
* flip_y ::
|
||||
* Setting this parameter to true maked the output image flipped
|
||||
* along the y-axis.
|
||||
|
||||
*
|
||||
* overlaps ::
|
||||
* Set this to true to generate SDF for glyphs having overlapping
|
||||
* contours. The overlapping support is limited to glyph which do
|
||||
* not have self intersecting contours. Also, removing overlaps
|
||||
* require a considerable amount of extra memory and this is not
|
||||
* valid while generating SDF from bitmap.
|
||||
*
|
||||
* @note:
|
||||
* It is valid for both `sdf' and `bsdf' renderer.
|
||||
* All properties except `overlaps' is valid for both `sdf' and
|
||||
* `bsdf' renderer.
|
||||
*
|
||||
*/
|
||||
typedef struct SDF_Renderer_Module_
|
||||
|
@ -51,9 +59,7 @@ FT_BEGIN_HEADER
|
|||
FT_UInt spread;
|
||||
FT_Bool flip_sign;
|
||||
FT_Bool flip_y;
|
||||
|
||||
/* @experimental fields: */
|
||||
FT_Int optimization;
|
||||
FT_Bool overlaps;
|
||||
|
||||
} SDF_Renderer_Module, *SDF_Renderer;
|
||||
|
||||
|
|
Loading…
Reference in New Issue