@ -398,6 +398,18 @@ int main(int arg, char **argv)
# ifndef STBTT_sqrt
# include <math.h>
# define STBTT_sqrt(x) sqrt(x)
# define STBTT_pow(x,y) pow(x,y)
# endif
# ifndef STBTT_cos
# include <math.h>
# define STBTT_cos(x) cos(x)
# define STBTT_acos(x) acos(x)
# endif
# ifndef STBTT_fabs
# include <math.h>
# define STBTT_fabs(x) fabs(x)
# endif
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
@ -418,7 +430,7 @@ int main(int arg, char **argv)
# endif
# ifndef STBTT_memcpy
# include <memory .h>
# include <string .h>
# define STBTT_memcpy memcpy
# define STBTT_memset memset
# endif
@ -623,7 +635,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
// The following structure is defined publically so you can declare one on
// the stack or as a global or etc, but you should treat it as opaque.
typedef struct stbtt_fontinfo
struct stbtt_fontinfo
{
void * userdata ;
unsigned char * data ; // pointer to .ttf file
@ -634,7 +646,7 @@ typedef struct stbtt_fontinfo
int loca , head , glyf , hhea , hmtx , kern ; // table locations as offset from start of .ttf
int index_map ; // a cmap mapping for our chosen character encoding
int indexToLocFormat ; // format needed to map from glyph index to glyph
} stbtt_fontinfo ;
} ;
STBTT_DEF int stbtt_InitFont ( stbtt_fontinfo * info , const unsigned char * data , int offset ) ;
// Given an offset into the file that defines a font, this function builds
@ -774,6 +786,10 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
// shift for the character
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter ( const stbtt_fontinfo * info , unsigned char * output , int out_w , int out_h , int out_stride , float scale_x , float scale_y , float shift_x , float shift_y , int oversample_x , int oversample_y , float * sub_x , float * sub_y , int codepoint ) ;
// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
// is performed (see stbtt_PackSetOversampling)
STBTT_DEF void stbtt_GetCodepointBitmapBox ( const stbtt_fontinfo * font , int codepoint , float scale_x , float scale_y , int * ix0 , int * iy0 , int * ix1 , int * iy1 ) ;
// get the bbox of the bitmap centered around the glyph origin; so the
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
@ -791,6 +807,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float
STBTT_DEF unsigned char * stbtt_GetGlyphBitmapSubpixel ( const stbtt_fontinfo * info , float scale_x , float scale_y , float shift_x , float shift_y , int glyph , int * width , int * height , int * xoff , int * yoff ) ;
STBTT_DEF void stbtt_MakeGlyphBitmap ( const stbtt_fontinfo * info , unsigned char * output , int out_w , int out_h , int out_stride , float scale_x , float scale_y , int glyph ) ;
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel ( const stbtt_fontinfo * info , unsigned char * output , int out_w , int out_h , int out_stride , float scale_x , float scale_y , float shift_x , float shift_y , int glyph ) ;
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter ( const stbtt_fontinfo * info , unsigned char * output , int out_w , int out_h , int out_stride , float scale_x , float scale_y , float shift_x , float shift_y , int oversample_x , int oversample_y , float * sub_x , float * sub_y , int glyph ) ;
STBTT_DEF void stbtt_GetGlyphBitmapBox ( const stbtt_fontinfo * font , int glyph , float scale_x , float scale_y , int * ix0 , int * iy0 , int * ix1 , int * iy1 ) ;
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel ( const stbtt_fontinfo * font , int glyph , float scale_x , float scale_y , float shift_x , float shift_y , int * ix0 , int * iy0 , int * ix1 , int * iy1 ) ;
@ -804,6 +821,14 @@ typedef struct
STBTT_DEF void stbtt_Rasterize ( stbtt__bitmap * result , float flatness_in_pixels , stbtt_vertex * vertices , int num_verts , float scale_x , float scale_y , float shift_x , float shift_y , int x_off , int y_off , int invert , void * userdata ) ;
//////////////////////////////////////////////////////////////////////////////
//
// Signed Distance Function rendering
STBTT_DEF unsigned char * stbtt_GetGlyphSDF ( const stbtt_fontinfo * info , float scale , int glyph , int padding , unsigned char onedge_value , float pixel_dist_scale , int * width , int * height , int * xoff , int * yoff ) ;
STBTT_DEF unsigned char * stbtt_GetCodepointSDF ( const stbtt_fontinfo * info , float scale , int codepoint , int padding , unsigned char onedge_value , float pixel_dist_scale , int * width , int * height , int * xoff , int * yoff ) ;
//////////////////////////////////////////////////////////////////////////////
//
// Finding the right font...
@ -1974,7 +1999,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
}
y_crossing + = dy * ( x2 - ( x1 + 1 ) ) ;
STBTT_assert ( fabs ( area ) < = 1.01f ) ;
STBTT_assert ( STBTT_ fabs( area ) < = 1.01f ) ;
scanline [ x2 ] + = area + sign * ( 1 - ( ( x2 - x2 ) + ( x_bottom - x2 ) ) / 2 ) * ( y1 - y_crossing ) ;
@ -2001,12 +2026,12 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
// that, we need to explicitly produce segments based on x positions.
// rename variables to clear pairs
float y0 = y_top ;
float x1 = ( float ) ( x ) ;
float x2 = ( float ) ( x + 1 ) ;
float x3 = xb ;
float y3 = y_bottom ;
float y1 , y2 ;
float x1 , x2 , x3 , y3 , y2 ;
y0 = y_top ;
x1 = ( float ) ( x ) ;
x2 = ( float ) ( x + 1 ) ;
x3 = xb ;
y3 = y_bottom ;
// x = e->x + e->dx * (y-y_top)
// (y-y_top) = (x - e->x) / e->dx
@ -2106,7 +2131,7 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
int m ;
sum + = scanline2 [ i ] ;
k = scanline [ i ] + sum ;
k = ( float ) fabs ( k ) * 255 + 0.5f ;
k = ( float ) STBTT_ fabs( k ) * 255 + 0.5f ;
m = ( int ) k ;
if ( m > 255 ) m = 255 ;
result - > pixels [ j * result - > stride + i ] = ( unsigned char ) m ;
@ -2850,6 +2875,29 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fon
return k ;
}
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter ( const stbtt_fontinfo * info , unsigned char * output , int out_w , int out_h , int out_stride , float scale_x , float scale_y , float shift_x , float shift_y , int prefilter_x , int prefilter_y , float * sub_x , float * sub_y , int glyph )
{
stbtt_MakeGlyphBitmapSubpixel ( info ,
output ,
out_w - ( prefilter_x - 1 ) ,
out_h - ( prefilter_y - 1 ) ,
out_stride ,
scale_x ,
scale_y ,
shift_x ,
shift_y ,
glyph ) ;
if ( prefilter_x > 1 )
stbtt__h_prefilter ( output , out_w , out_h , out_stride , prefilter_x ) ;
if ( prefilter_y > 1 )
stbtt__v_prefilter ( output , out_w , out_h , out_stride , prefilter_y ) ;
* sub_x = stbtt__oversample_shift ( prefilter_x ) ;
* sub_y = stbtt__oversample_shift ( prefilter_y ) ;
}
// rects array must be big enough to accommodate all characters in the given ranges
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects ( stbtt_pack_context * spc , stbtt_fontinfo * info , stbtt_pack_range * ranges , int num_ranges , stbrp_rect * rects )
{
@ -3012,6 +3060,382 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, i
* xpos + = b - > xadvance ;
}
//////////////////////////////////////////////////////////////////////////////
//
// sdf computation
//
# define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
# define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
static int stbtt__ray_intersect_bezier ( float orig [ 2 ] , float ray [ 2 ] , float q0 [ 2 ] , float q1 [ 2 ] , float q2 [ 2 ] , float hits [ 2 ] [ 2 ] )
{
float q0perp = q0 [ 1 ] * ray [ 0 ] - q0 [ 0 ] * ray [ 1 ] ;
float q1perp = q1 [ 1 ] * ray [ 0 ] - q1 [ 0 ] * ray [ 1 ] ;
float q2perp = q2 [ 1 ] * ray [ 0 ] - q2 [ 0 ] * ray [ 1 ] ;
float roperp = orig [ 1 ] * ray [ 0 ] - orig [ 0 ] * ray [ 1 ] ;
float a = q0perp - 2 * q1perp + q2perp ;
float b = q1perp - q0perp ;
float c = q0perp - roperp ;
float s0 = 0. , s1 = 0. ;
int num_s = 0 ;
if ( a ! = 0.0 ) {
float discr = b * b - a * c ;
if ( discr > 0.0 ) {
float rcpna = - 1 / a ;
float d = ( float ) sqrt ( discr ) ;
s0 = ( b + d ) * rcpna ;
s1 = ( b - d ) * rcpna ;
if ( s0 > = 0.0 & & s0 < = 1.0 )
num_s = 1 ;
if ( d > 0.0 & & s1 > = 0.0 & & s1 < = 1.0 ) {
if ( num_s = = 0 ) s0 = s1 ;
+ + num_s ;
}
}
} else {
// 2*b*s + c = 0
// s = -c / (2*b)
s0 = c / ( - 2 * b ) ;
if ( s0 > = 0.0 & & s0 < = 1.0 )
num_s = 1 ;
}
if ( num_s = = 0 )
return 0 ;
else {
float rcp_len2 = 1 / ( ray [ 0 ] * ray [ 0 ] + ray [ 1 ] * ray [ 1 ] ) ;
float rayn_x = ray [ 0 ] * rcp_len2 , rayn_y = ray [ 1 ] * rcp_len2 ;
float q0d = q0 [ 0 ] * rayn_x + q0 [ 1 ] * rayn_y ;
float q1d = q1 [ 0 ] * rayn_x + q1 [ 1 ] * rayn_y ;
float q2d = q2 [ 0 ] * rayn_x + q2 [ 1 ] * rayn_y ;
float rod = orig [ 0 ] * rayn_x + orig [ 1 ] * rayn_y ;
float q10d = q1d - q0d ;
float q20d = q2d - q0d ;
float q0rd = q0d - rod ;
hits [ 0 ] [ 0 ] = q0rd + s0 * ( 2.0f - 2.0f * s0 ) * q10d + s0 * s0 * q20d ;
hits [ 0 ] [ 1 ] = a * s0 + b ;
if ( num_s > 1 ) {
hits [ 1 ] [ 0 ] = q0rd + s1 * ( 2.0f - 2.0f * s1 ) * q10d + s1 * s1 * q20d ;
hits [ 1 ] [ 1 ] = a * s1 + b ;
return 2 ;
} else {
return 1 ;
}
}
}
static int equal ( float * a , float * b )
{
return ( a [ 0 ] = = b [ 0 ] & & a [ 1 ] = = b [ 1 ] ) ;
}
static int stbtt__compute_crossings_x ( float x , float y , int nverts , stbtt_vertex * verts )
{
int i ;
float orig [ 2 ] , ray [ 2 ] = { 1 , 0 } ;
float y_frac ;
int winding = 0 ;
orig [ 0 ] = x ;
orig [ 1 ] = y ;
// make sure y never passes through a vertex of the shape
y_frac = ( float ) fmod ( y , 1.0f ) ;
if ( y_frac < 0.01f )
y + = 0.01f ;
else if ( y_frac > 0.99f )
y - = 0.01f ;
orig [ 1 ] = y ;
// test a ray from (-infinity,y) to (x,y)
for ( i = 0 ; i < nverts ; + + i ) {
if ( verts [ i ] . type = = STBTT_vline ) {
int x0 = ( int ) verts [ i - 1 ] . x , y0 = ( int ) verts [ i - 1 ] . y ;
int x1 = ( int ) verts [ i ] . x , y1 = ( int ) verts [ i ] . y ;
if ( y > STBTT_min ( y0 , y1 ) & & y < STBTT_max ( y0 , y1 ) & & x > STBTT_min ( x0 , x1 ) ) {
float x_inter = ( y - y0 ) / ( y1 - y0 ) * ( x1 - x0 ) + x0 ;
if ( x_inter < x )
winding + = ( y0 < y1 ) ? 1 : - 1 ;
}
}
if ( verts [ i ] . type = = STBTT_vcurve ) {
int x0 = ( int ) verts [ i - 1 ] . x , y0 = ( int ) verts [ i - 1 ] . y ;
int x1 = ( int ) verts [ i ] . cx , y1 = ( int ) verts [ i ] . cy ;
int x2 = ( int ) verts [ i ] . x , y2 = ( int ) verts [ i ] . y ;
int ax = STBTT_min ( x0 , STBTT_min ( x1 , x2 ) ) , ay = STBTT_min ( y0 , STBTT_min ( y1 , y2 ) ) ;
int by = STBTT_max ( y0 , STBTT_max ( y1 , y2 ) ) ;
if ( y > ay & & y < by & & x > ax ) {
float q0 [ 2 ] , q1 [ 2 ] , q2 [ 2 ] ;
float hits [ 2 ] [ 2 ] ;
q0 [ 0 ] = ( float ) x0 ;
q0 [ 1 ] = ( float ) y0 ;
q1 [ 0 ] = ( float ) x1 ;
q1 [ 1 ] = ( float ) y1 ;
q2 [ 0 ] = ( float ) x2 ;
q2 [ 1 ] = ( float ) y2 ;
if ( equal ( q0 , q1 ) | | equal ( q1 , q2 ) ) {
x0 = ( int ) verts [ i - 1 ] . x ;
y0 = ( int ) verts [ i - 1 ] . y ;
x1 = ( int ) verts [ i ] . x ;
y1 = ( int ) verts [ i ] . y ;
if ( y > STBTT_min ( y0 , y1 ) & & y < STBTT_max ( y0 , y1 ) & & x > STBTT_min ( x0 , x1 ) ) {
float x_inter = ( y - y0 ) / ( y1 - y0 ) * ( x1 - x0 ) + x0 ;
if ( x_inter < x )
winding + = ( y0 < y1 ) ? 1 : - 1 ;
}
} else {
int num_hits = stbtt__ray_intersect_bezier ( orig , ray , q0 , q1 , q2 , hits ) ;
if ( num_hits > = 1 )
if ( hits [ 0 ] [ 0 ] < 0 )
winding + = ( hits [ 0 ] [ 1 ] < 0 ? - 1 : 1 ) ;
if ( num_hits > = 2 )
if ( hits [ 1 ] [ 0 ] < 0 )
winding + = ( hits [ 1 ] [ 1 ] < 0 ? - 1 : 1 ) ;
}
}
}
}
return winding ;
}
static float stbtt__cuberoot ( float x )
{
if ( x < 0 )
return - ( float ) STBTT_pow ( - x , 1.0f / 3.0f ) ;
else
return ( float ) STBTT_pow ( x , 1.0f / 3.0f ) ;
}
// x^3 + c*x^2 + b*x + a = 0
static int stbtt__solve_cubic ( float a , float b , float c , float * r )
{
float s = - a / 3 ;
float p = b - a * a / 3 ;
float q = a * ( 2 * a * a - 9 * b ) / 27 + c ;
float p3 = p * p * p ;
float d = q * q + 4 * p3 / 27 ;
if ( d > = 0 ) {
float z = ( float ) STBTT_sqrt ( d ) ;
float u = ( - q + z ) / 2 ;
float v = ( - q - z ) / 2 ;
u = stbtt__cuberoot ( u ) ;
v = stbtt__cuberoot ( v ) ;
r [ 0 ] = s + u + v ;
return 1 ;
} else {
float u = ( float ) STBTT_sqrt ( - p / 3 ) ;
float v = ( float ) STBTT_acos ( - STBTT_sqrt ( - 27 / p3 ) * q / 2 ) / 3 ; // p3 must be negative, since d is negative
float m = ( float ) STBTT_cos ( v ) ;
float n = ( float ) STBTT_cos ( v - 3.141592 / 2 ) * 1.732050808f ;
r [ 0 ] = s + u * 2 * m ;
r [ 1 ] = s - u * ( m + n ) ;
r [ 2 ] = s - u * ( m - n ) ;
//STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
//STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
//STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
return 3 ;
}
}
STBTT_DEF unsigned char * stbtt_GetGlyphSDF ( const stbtt_fontinfo * info , float scale , int glyph , int padding , unsigned char onedge_value , float pixel_dist_scale , int * width , int * height , int * xoff , int * yoff )
{
float scale_x = scale , scale_y = scale ;
int ix0 , iy0 , ix1 , iy1 ;
int w , h ;
unsigned char * data ;
// if one scale is 0, use same scale for both
if ( scale_x = = 0 ) scale_x = scale_y ;
if ( scale_y = = 0 ) {
if ( scale_x = = 0 ) return NULL ; // if both scales are 0, return NULL
scale_y = scale_x ;
}
stbtt_GetGlyphBitmapBoxSubpixel ( info , glyph , scale , scale , 0.0f , 0.0f , & ix0 , & iy0 , & ix1 , & iy1 ) ;
// if empty, return NULL
if ( ix0 = = ix1 | | iy0 = = iy1 )
return NULL ;
ix0 - = padding ;
iy0 - = padding ;
ix1 + = padding ;
iy1 + = padding ;
w = ( ix1 - ix0 ) ;
h = ( iy1 - iy0 ) ;
if ( width ) * width = w ;
if ( height ) * height = h ;
if ( xoff ) * xoff = ix0 ;
if ( yoff ) * yoff = iy0 ;
// invert for y-downwards bitmaps
scale_y = - scale_y ;
{
int x , y , i , j ;
float * precompute ;
stbtt_vertex * verts ;
int num_verts = stbtt_GetGlyphShape ( info , glyph , & verts ) ;
data = ( unsigned char * ) STBTT_malloc ( w * h , info - > userdata ) ;
precompute = ( float * ) STBTT_malloc ( num_verts * sizeof ( float ) , info - > userdata ) ;
for ( i = 0 , j = num_verts - 1 ; i < num_verts ; j = i + + ) {
if ( verts [ i ] . type = = STBTT_vline ) {
float x0 = verts [ i ] . x * scale_x , y0 = verts [ i ] . y * scale_y ;
float x1 = verts [ j ] . x * scale_x , y1 = verts [ j ] . y * scale_y ;
float dist = ( float ) STBTT_sqrt ( ( x1 - x0 ) * ( x1 - x0 ) + ( y1 - y0 ) * ( y1 - y0 ) ) ;
precompute [ i ] = ( dist = = 0 ) ? 0.0f : 1.0f / dist ;
} else if ( verts [ i ] . type = = STBTT_vcurve ) {
float x2 = verts [ j ] . x * scale_x , y2 = verts [ j ] . y * scale_y ;
float x1 = verts [ i ] . cx * scale_x , y1 = verts [ i ] . cy * scale_y ;
float x0 = verts [ i ] . x * scale_x , y0 = verts [ i ] . y * scale_y ;
float bx = x0 - 2 * x1 + x2 , by = y0 - 2 * y1 + y2 ;
float len2 = bx * bx + by * by ;
if ( len2 ! = 0.0f )
precompute [ i ] = 1.0f / ( bx * bx + by * by ) ;
else
precompute [ i ] = 0.0f ;
} else
precompute [ i ] = 0.0f ;
}
for ( y = iy0 ; y < iy1 ; + + y ) {
for ( x = ix0 ; x < ix1 ; + + x ) {
float val ;
float min_dist = 999999.0f ;
float sx = ( float ) x + 0.5f ;
float sy = ( float ) y + 0.5f ;
float x_gspace = ( sx / scale_x ) ;
float y_gspace = ( sy / scale_y ) ;
int winding = stbtt__compute_crossings_x ( x_gspace , y_gspace , num_verts , verts ) ; // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
for ( i = 0 ; i < num_verts ; + + i ) {
float x0 = verts [ i ] . x * scale_x , y0 = verts [ i ] . y * scale_y ;
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
float dist2 = ( x0 - sx ) * ( x0 - sx ) + ( y0 - sy ) * ( y0 - sy ) ;
if ( dist2 < min_dist * min_dist )
min_dist = ( float ) STBTT_sqrt ( dist2 ) ;
if ( verts [ i ] . type = = STBTT_vline ) {
float x1 = verts [ i - 1 ] . x * scale_x , y1 = verts [ i - 1 ] . y * scale_y ;
// coarse culling against bbox
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
float dist = ( float ) STBTT_fabs ( ( x1 - x0 ) * ( y0 - sy ) - ( y1 - y0 ) * ( x0 - sx ) ) * precompute [ i ] ;
STBTT_assert ( i ! = 0 ) ;
if ( dist < min_dist ) {
// check position along line
// x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
// minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
float dx = x1 - x0 , dy = y1 - y0 ;
float px = x0 - sx , py = y0 - sy ;
// minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
// derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
float t = - ( px * dx + py * dy ) / ( dx * dx + dy * dy ) ;
if ( t > = 0.0f & & t < = 1.0f )
min_dist = dist ;
}
} else if ( verts [ i ] . type = = STBTT_vcurve ) {
float x2 = verts [ i - 1 ] . x * scale_x , y2 = verts [ i - 1 ] . y * scale_y ;
float x1 = verts [ i ] . cx * scale_x , y1 = verts [ i ] . cy * scale_y ;
float box_x0 = STBTT_min ( STBTT_min ( x0 , x1 ) , x2 ) ;
float box_y0 = STBTT_min ( STBTT_min ( y0 , y1 ) , y2 ) ;
float box_x1 = STBTT_max ( STBTT_max ( x0 , x1 ) , x2 ) ;
float box_y1 = STBTT_max ( STBTT_max ( y0 , y1 ) , y2 ) ;
// coarse culling against bbox to avoid computing cubic unnecessarily
if ( sx > box_x0 - min_dist & & sx < box_x1 + min_dist & & sy > box_y0 - min_dist & & sy < box_y1 + min_dist ) {
int num = 0 ;
float ax = x1 - x0 , ay = y1 - y0 ;
float bx = x0 - 2 * x1 + x2 , by = y0 - 2 * y1 + y2 ;
float mx = x0 - sx , my = y0 - sy ;
float res [ 3 ] , px , py , t , it ;
float a_inv = precompute [ i ] ;
if ( a_inv = = 0.0 ) { // if a_inv is 0, it's 2nd degree so use quadratic formula
float a = 3 * ( ax * bx + ay * by ) ;
float b = 2 * ( ax * ax + ay * ay ) + ( mx * bx + my * by ) ;
float c = mx * ax + my * ay ;
if ( a = = 0.0 ) { // if a is 0, it's linear
if ( b ! = 0.0 ) {
res [ num + + ] = - c / b ;
}
} else {
float discriminant = b * b - 4 * a * c ;
if ( discriminant < 0 )
num = 0 ;
else {
float root = ( float ) STBTT_sqrt ( discriminant ) ;
res [ 0 ] = ( - b - root ) / ( 2 * a ) ;
res [ 1 ] = ( - b + root ) / ( 2 * a ) ;
num = 2 ; // don't bother distinguishing 1-solution case, as code below will still work
}
}
} else {
float b = 3 * ( ax * bx + ay * by ) * a_inv ; // could precompute this as it doesn't depend on sample point
float c = ( 2 * ( ax * ax + ay * ay ) + ( mx * bx + my * by ) ) * a_inv ;
float d = ( mx * ax + my * ay ) * a_inv ;
num = stbtt__solve_cubic ( b , c , d , res ) ;
}
if ( num > = 1 & & res [ 0 ] > = 0.0f & & res [ 0 ] < = 1.0f ) {
t = res [ 0 ] , it = 1.0f - t ;
px = it * it * x0 + 2 * t * it * x1 + t * t * x2 ;
py = it * it * y0 + 2 * t * it * y1 + t * t * y2 ;
dist2 = ( px - sx ) * ( px - sx ) + ( py - sy ) * ( py - sy ) ;
if ( dist2 < min_dist * min_dist )
min_dist = ( float ) STBTT_sqrt ( dist2 ) ;
}
if ( num > = 2 & & res [ 1 ] > = 0.0f & & res [ 1 ] < = 1.0f ) {
t = res [ 1 ] , it = 1.0f - t ;
px = it * it * x0 + 2 * t * it * x1 + t * t * x2 ;
py = it * it * y0 + 2 * t * it * y1 + t * t * y2 ;
dist2 = ( px - sx ) * ( px - sx ) + ( py - sy ) * ( py - sy ) ;
if ( dist2 < min_dist * min_dist )
min_dist = ( float ) STBTT_sqrt ( dist2 ) ;
}
if ( num > = 3 & & res [ 2 ] > = 0.0f & & res [ 2 ] < = 1.0f ) {
t = res [ 2 ] , it = 1.0f - t ;
px = it * it * x0 + 2 * t * it * x1 + t * t * x2 ;
py = it * it * y0 + 2 * t * it * y1 + t * t * y2 ;
dist2 = ( px - sx ) * ( px - sx ) + ( py - sy ) * ( py - sy ) ;
if ( dist2 < min_dist * min_dist )
min_dist = ( float ) STBTT_sqrt ( dist2 ) ;
}
}
}
}
if ( winding = = 0 )
min_dist = - min_dist ; // if outside the shape, value is negative
val = onedge_value + pixel_dist_scale * min_dist ;
if ( val < 0 )
val = 0 ;
else if ( val > 255 )
val = 255 ;
data [ ( y - iy0 ) * w + ( x - ix0 ) ] = ( unsigned char ) val ;
}
}
STBTT_free ( precompute , info - > userdata ) ;
STBTT_free ( verts , info - > userdata ) ;
}
return data ;
}
STBTT_DEF unsigned char * stbtt_GetCodepointSDF ( const stbtt_fontinfo * info , float scale , int codepoint , int padding , unsigned char onedge_value , float pixel_dist_scale , int * width , int * height , int * xoff , int * yoff )
{
return stbtt_GetGlyphSDF ( info , scale , stbtt_FindGlyphIndex ( info , codepoint ) , padding , onedge_value , pixel_dist_scale , width , height , xoff , yoff ) ;
}
//////////////////////////////////////////////////////////////////////////////
//