mirror of
https://github.com/nothings/stb
synced 2024-12-15 12:22:55 +03:00
Initial SDF support
This commit is contained in:
parent
ad57cd038b
commit
5defc65c23
446
stb_truetype.h
446
stb_truetype.h
@ -398,6 +398,18 @@ int main(int arg, char **argv)
|
|||||||
#ifndef STBTT_sqrt
|
#ifndef STBTT_sqrt
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#define STBTT_sqrt(x) sqrt(x)
|
#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
|
#endif
|
||||||
|
|
||||||
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
|
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
|
||||||
@ -418,7 +430,7 @@ int main(int arg, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STBTT_memcpy
|
#ifndef STBTT_memcpy
|
||||||
#include <memory.h>
|
#include <string.h>
|
||||||
#define STBTT_memcpy memcpy
|
#define STBTT_memcpy memcpy
|
||||||
#define STBTT_memset memset
|
#define STBTT_memset memset
|
||||||
#endif
|
#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 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.
|
// the stack or as a global or etc, but you should treat it as opaque.
|
||||||
typedef struct stbtt_fontinfo
|
struct stbtt_fontinfo
|
||||||
{
|
{
|
||||||
void * userdata;
|
void * userdata;
|
||||||
unsigned char * data; // pointer to .ttf file
|
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 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 index_map; // a cmap mapping for our chosen character encoding
|
||||||
int indexToLocFormat; // format needed to map from glyph index to glyph
|
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);
|
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
|
// 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
|
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
|
||||||
// shift for the character
|
// 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);
|
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
|
// 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
|
// 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 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_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_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_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);
|
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);
|
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...
|
// 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));
|
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);
|
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.
|
// that, we need to explicitly produce segments based on x positions.
|
||||||
|
|
||||||
// rename variables to clear pairs
|
// rename variables to clear pairs
|
||||||
float y0 = y_top;
|
float x1,x2,x3,y3,y2;
|
||||||
float x1 = (float) (x);
|
y0 = y_top;
|
||||||
float x2 = (float) (x+1);
|
x1 = (float) (x);
|
||||||
float x3 = xb;
|
x2 = (float) (x+1);
|
||||||
float y3 = y_bottom;
|
x3 = xb;
|
||||||
float y1,y2;
|
y3 = y_bottom;
|
||||||
|
|
||||||
// x = e->x + e->dx * (y-y_top)
|
// x = e->x + e->dx * (y-y_top)
|
||||||
// (y-y_top) = (x - e->x) / e->dx
|
// (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;
|
int m;
|
||||||
sum += scanline2[i];
|
sum += scanline2[i];
|
||||||
k = scanline[i] + sum;
|
k = scanline[i] + sum;
|
||||||
k = (float) fabs(k)*255 + 0.5f;
|
k = (float) STBTT_fabs(k)*255 + 0.5f;
|
||||||
m = (int) k;
|
m = (int) k;
|
||||||
if (m > 255) m = 255;
|
if (m > 255) m = 255;
|
||||||
result->pixels[j*result->stride + i] = (unsigned char) m;
|
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;
|
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
|
// 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)
|
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;
|
*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);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user