Oh boy, this is a mess.

This commit is contained in:
Marisa the Magician 2022-09-22 20:44:00 +02:00
commit 5ff8bd2367

123
mkfont.c
View file

@ -49,10 +49,13 @@
uint8_t pal[768];
int palsize = 0;
int xupshift = 0;
int rightshift = 0;
int bordshift = 0;
int tewi_hotfix = 0; // U+0309 and U+030A glyphs are offset incorrectly
// and the entire font height needs to be cropped
int miniwi_hotfix = 0; // U+01C2 glyph is offset incorrect
// this font's height also needs a crop
uint32_t endianswap( uint32_t n )
{
// if we're in a big endian system, we don't need this
@ -94,9 +97,9 @@ int writepng( const char *filename, uint8_t *fdata, int w, int h, int p )
png_set_IHDR(pngp,infp,w,h,8,palsize?PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_GA,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
if ( xupshift || rightshift || bordshift )
if ( bordshift )
{
uint32_t grabs[2] = {endianswap(rightshift+bordshift),endianswap(xupshift+bordshift)};
uint32_t grabs[2] = {endianswap(bordshift),endianswap(bordshift)};
png_unknown_chunk grab =
{
.name = "grAb",
@ -118,10 +121,10 @@ FT_Library ftlib;
FT_Face fnt;
int iw, ih;
int w, h, pxsiz, datsiz;
int w, h, datsiz;
uint8_t *idata;
int autosize = 0;
int calcsize = 1;
int gradient = 0;
int upshift = 0;
@ -191,9 +194,9 @@ int draw_glyph( FT_Bitmap *bmp, uint8_t v, int px, int py, int ox, int oy )
if ( v == 255 )
{
float a;
int ofs = j+oy+(upshift+1);
int ofs = j+oy+(upshift+tewi_hotfix+miniwi_hotfix);
if ( ofs < 0 ) a = 0.;
else a = ofs/(float)(h+upshift+1);
else a = ofs/(float)(h-1);
if ( (gradient&3) == 1 ) rv = lerpg(1.-a);
else if ( (gradient&3) == 2 ) rv = lerpg(a);
else if ( (gradient&3) == 3 ) rv = lerpg((a>.5)?((1.-a)*2.):(a*2.));
@ -343,10 +346,10 @@ const char grads[8][20] =
int main( int argc, char **argv )
{
if ( argc < 4 )
if ( argc < 3 )
{
fprintf(stderr,"usage: mkfontsingle <font name> <pxsize> <wxh|auto>"
" <unicode range (hex)> [gradient type] [color palette] [-palinv]\n");
fprintf(stderr,"usage: mkfont <font name> <pxsize> <unicode range (hex)>"
" [gradient type] [color palette] [-palinv]\n");
return 1;
}
if ( FT_Init_FreeType(&ftlib) )
@ -355,18 +358,20 @@ int main( int argc, char **argv )
return 2;
}
uint32_t range[2] = {0x0000,0x00FF};
int pxsiz;
sscanf(argv[2],"%d",&pxsiz);
if ( !strcmp(argv[3],"auto") ) autosize = 1;
else sscanf(argv[3],"%dx%d",&w,&h);
sscanf(argv[4],"%x-%x",&range[0],&range[1]);
if ( argc > 5 ) sscanf(argv[5],"%d",&gradient);
if ( argc > 7 ) palinv = !strcmp(argv[7],"-palinv");
if ( argc > 6 ) loadpalette(argv[6]);
sscanf(argv[3],"%x-%x",&range[0],&range[1]);
if ( argc > 4 ) sscanf(argv[4],"%d",&gradient);
if ( argc > 6 ) palinv = !strcmp(argv[6],"-palinv");
if ( argc > 5 ) loadpalette(argv[5]);
if ( FT_New_Face(ftlib,argv[1],0,&fnt) )
{
fprintf(stderr,"error: failed to open font '%s'\n",argv[1]);
return 4;
}
fprintf(stderr,"info: loaded font \'%s %s\'.\n",fnt->family_name,fnt->style_name);
if ( !strcmp(fnt->family_name,"tewi") ) tewi_hotfix = 1;
else if ( !strcmp(fnt->family_name,"miniwi") ) miniwi_hotfix = 1;
if ( FT_Set_Pixel_Sizes(fnt,0,pxsiz) )
{
if ( fnt->num_fixed_sizes <= 0 )
@ -391,10 +396,11 @@ int main( int argc, char **argv )
return 8;
}
}
h = (fnt->size->metrics.height>>6)-tewi_hotfix-miniwi_hotfix;
FT_Select_Charmap(fnt,FT_ENCODING_UNICODE);
// first pass to compute baseline upshift
upshift = 65535;
for ( uint32_t i=range[0]; i<=range[1]; i++ )
for ( uint32_t i=0; i<=0xFFFF; i++ )
{
FT_UInt glyph = FT_Get_Char_Index(fnt,i);
if ( !glyph || FT_Load_Glyph(fnt,glyph,LOADFLAGS) ) continue;
@ -407,48 +413,13 @@ int main( int argc, char **argv )
if ( gshift < upshift ) upshift = gshift;
}
fprintf(stderr,"info: estimated baseline upshift is %d.\n",upshift);
// second pass to compute "real" upshift, which is used for the grAb Y offset
// as well as the "rightshift" for the X offset
xupshift = 65535;
for ( uint32_t i=range[0]; i<=range[1]; i++ )
// second pass to compute the maximum cell size (for memory allocation)
if ( calcsize )
{
FT_UInt glyph = FT_Get_Char_Index(fnt,i);
if ( !glyph || FT_Load_Glyph(fnt,glyph,LOADFLAGS) ) continue;
FT_Render_Glyph(fnt->glyph,RENDERMODE);
int valid = 0;
for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ )
valid |= valid_row(&fnt->glyph->bitmap,j);
if ( !valid ) continue;
int xx = fnt->glyph->bitmap_left;
if ( -xx > rightshift ) rightshift = -xx;
int yy = upshift+1+(pxsiz-fnt->glyph->bitmap_top);
for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ )
{
if ( !valid_row(&fnt->glyph->bitmap,j) ) yy++;
else break;
}
if ( yy < 0 )
{
int xup = -yy;
if ( xup < xupshift ) xupshift = xup;
}
}
if ( xupshift == 65535 ) xupshift = 0;
if ( xupshift )
{
fprintf(stderr,"info: real upshift is %d.\n",upshift+xupshift);
fprintf(stderr,"info: grAb Y offset %d will be used.\n",xupshift);
}
if ( rightshift )
fprintf(stderr,"info: right shift detected, grAb X offset %d will be used.\n",rightshift);
// third pass to compute the maximum cell size (for memory allocation)
if ( autosize )
{
h = (fnt->size->metrics.height>>6)+1;
if ( FT_IS_FIXED_WIDTH(fnt) )
{
w = fnt->size->metrics.max_advance>>6;
autosize = 0; // don't readjust per-glyph
calcsize = 0; // don't readjust per-glyph
}
else for ( uint32_t i=range[0]; i<=range[1]; i++ )
{
@ -457,8 +428,8 @@ int main( int argc, char **argv )
FT_Render_Glyph(fnt->glyph,RENDERMODE);
int adv = fnt->glyph->linearHoriAdvance>>16;
int adv2 = fnt->glyph->advance.x>>6;
if ( !adv ) adv = adv2;
if ( (adv+rightshift) > w ) w = adv+rightshift;
if ( adv2 ) adv = adv2;
if ( adv > w ) w = adv;
}
fprintf(stderr,"info: max cell size is %dx%d.\n",w,h);
}
@ -483,37 +454,41 @@ int main( int argc, char **argv )
for ( unsigned j=0; j<fnt->glyph->bitmap.rows; j++ )
valid |= valid_row(&fnt->glyph->bitmap,j);
if ( !valid ) continue;
if ( autosize )
if ( calcsize )
{
// readjust cell width (but not height) for this character
int adv = fnt->glyph->linearHoriAdvance>>16;
int adv2 = fnt->glyph->advance.x>>6;
if ( !adv ) adv = adv2;
w = adv+rightshift;
if ( adv2 ) adv = adv2;
w = adv;
iw = w+((gradient&4)?2:1);
}
int xx = rightshift;
int yy = upshift+xupshift+1;
int xx = 0;
int yy = upshift+tewi_hotfix+miniwi_hotfix;
if ( tewi_hotfix && ((i != 0x0309) && (i != 0x030A)) )
fnt->glyph->bitmap_top++;
if ( miniwi_hotfix && (i == 0x01C2) )
fnt->glyph->bitmap_top++;
valid = 0;
oob = 0;
if ( gradient&4 )
{
// draw outline first
draw_glyph(&fnt->glyph->bitmap,0,xx,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy+2,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+2,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+2,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
valid = draw_glyph(&fnt->glyph->bitmap,255,xx+1,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx,yy+2,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+2,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+2,yy+2,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
valid = draw_glyph(&fnt->glyph->bitmap,255,xx+1,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
}
else
{
// draw drop shadow first
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+1,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
valid = draw_glyph(&fnt->glyph->bitmap,255,xx,yy,fnt->glyph->bitmap_left,pxsiz-fnt->glyph->bitmap_top);
draw_glyph(&fnt->glyph->bitmap,0,xx+1,yy+1,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
valid = draw_glyph(&fnt->glyph->bitmap,255,xx,yy,fnt->glyph->bitmap_left,h-fnt->glyph->bitmap_top);
}
if ( valid )
{