From 0d2a0c615a9c52ed0cacc9dd1ce99025b129c768 Mon Sep 17 00:00:00 2001 From: Shpoike Date: Sat, 11 Feb 2023 05:01:56 +0000 Subject: [PATCH] Eukara expressed an interest in loading fonts without any antialiasing. --- engine/client/pr_menu.c | 19 +++++-- engine/client/r_2d.c | 23 +++++--- engine/client/renderer.c | 2 + engine/client/sbar.c | 2 +- engine/client/screen.h | 3 +- engine/gl/gl_font.c | 116 +++++++++++++++++++++++++++++++-------- 6 files changed, 127 insertions(+), 38 deletions(-) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index e89109309..1e58159cb 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -105,6 +105,7 @@ struct { char facename[MAX_OSPATH]; float scale; //poop int outline; //argh + unsigned int fontflags; //erk int sizes; int size[FONT_SIZES]; struct font_s *font[FONT_SIZES]; @@ -233,7 +234,7 @@ void PR_ReloadFonts(qboolean reload) { //otherwise load it. for (j = 0; j < fontslot[i].sizes; j++) { - fontslot[i].font[j] = Font_LoadFont(fontslot[i].facename, fontslot[i].size[j], fontslot[i].scale, fontslot[i].outline); + fontslot[i].font[j] = Font_LoadFont(fontslot[i].facename, fontslot[i].size[j], fontslot[i].scale, fontslot[i].outline, fontslot[i].fontflags); } } } @@ -333,7 +334,7 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (qrenderer > QR_NONE) { for (i = 0; i < fontslot[slotnum].sizes; i++) - fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline); + fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline, fontslot[slotnum].fontflags); } G_FLOAT(OFS_RETURN) = slotnum; @@ -342,7 +343,7 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g #ifdef HAVE_LEGACY void CL_LoadFont_f(void) { - extern cvar_t r_font_postprocess_outline; + extern cvar_t r_font_postprocess_outline, r_font_postprocess_mono; //console command for compat with dp/debug. if (Cmd_Argc() == 1) { @@ -418,6 +419,8 @@ void CL_LoadFont_f(void) fontslot[slotnum].scale = 1; fontslot[slotnum].sizes = 0; fontslot[slotnum].outline = r_font_postprocess_outline.ival; //locked in at definition, so different fonts can have different settings even with vid_reload going on. + fontslot[slotnum].fontflags = 0 | + (r_font_postprocess_mono.ival?FONT_MONO:0); } if (!*facename) return; @@ -437,6 +440,14 @@ void CL_LoadFont_f(void) fontslot[slotnum].outline = atoi(Cmd_Argv(sizenum++)); continue; } + if (!strcmp(a, "mono")) + { + if (atoi(Cmd_Argv(sizenum++))) + fontslot[slotnum].fontflags |= FONT_MONO; + else + fontslot[slotnum].fontflags &= ~FONT_MONO; + continue; + } if (!strcmp(a, "blur")) { //fontslot[slotnum].blur = atoi(Cmd_Argv(sizenum++)); @@ -471,7 +482,7 @@ void CL_LoadFont_f(void) if (qrenderer > QR_NONE) { for (i = 0; i < fontslot[slotnum].sizes; i++) - fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline); + fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline, fontslot[slotnum].fontflags); } //FIXME: slotnum0==default is problematic. diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 5564f4134..8348da40b 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -56,7 +56,7 @@ struct extern cvar_t scr_conalpha; extern cvar_t gl_conback; extern cvar_t gl_font, con_textfont; -extern cvar_t r_font_postprocess_outline; +extern cvar_t r_font_postprocess_outline, r_font_postprocess_mono; extern cvar_t gl_screenangle; extern cvar_t vid_minsize; extern cvar_t vid_conautoscale; @@ -167,6 +167,7 @@ void R2D_Shutdown(void) Cvar_Unhook(&con_textfont); Cvar_Unhook(&gl_font); Cvar_Unhook(&r_font_postprocess_outline); + Cvar_Unhook(&r_font_postprocess_mono); Cvar_Unhook(&vid_conautoscale); Cvar_Unhook(&gl_screenangle); Cvar_Unhook(&vid_conheight); @@ -444,6 +445,7 @@ void R2D_Init(void) Cvar_Hook(&con_textfont, R2D_Font_Callback); Cvar_Hook(&gl_font, R2D_Font_Callback); Cvar_Hook(&r_font_postprocess_outline, R2D_Font_Callback); + Cvar_Hook(&r_font_postprocess_mono, R2D_Font_Callback); Cvar_Hook(&vid_conautoscale, R2D_Conautoscale_Callback); Cvar_Hook(&gl_screenangle, R2D_ScreenAngle_Callback); Cvar_Hook(&vid_conheight, R2D_Conheight_Callback); @@ -1137,6 +1139,7 @@ void R2D_Font_Changed(void) { float tsize; const char *con_font_name = con_textfont.string; + unsigned int flags; if (!con_textsize.modified) return; if (!*con_font_name) @@ -1170,6 +1173,10 @@ void R2D_Font_Changed(void) if (qrenderer == QR_NONE) return; + flags = 0; + if (r_font_postprocess_mono.ival) + flags |= FONT_MONO; + if (!strcmp(gl_font.string, "?")) { #ifndef AVAIL_FREETYPE @@ -1184,9 +1191,9 @@ void R2D_Font_Changed(void) LOGFONTW lf = {0}; CHOOSEFONTW cf = {sizeof(cf)}; extern HWND mainwindow; - font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival); + font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival, flags); if (tsize != 8) - font_console = Font_LoadFont("", tsize, 1, r_font_postprocess_outline.ival); + font_console = Font_LoadFont("", tsize, 1, r_font_postprocess_outline.ival, flags); if (!font_console) font_console = font_default; @@ -1230,19 +1237,19 @@ void R2D_Font_Changed(void) } if (COM_FCheckExists("fonts/qfont.kfont")) - font_menu = Font_LoadFont("qfont", 20, 1, r_font_postprocess_outline.ival); + font_menu = Font_LoadFont("qfont", 20, 1, r_font_postprocess_outline.ival, flags); else font_menu = NULL; - font_default = Font_LoadFont(gl_font.string, 8, 1, r_font_postprocess_outline.ival); + font_default = Font_LoadFont(gl_font.string, 8, 1, r_font_postprocess_outline.ival, flags); if (!font_default && *gl_font.string) - font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival); + font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival, flags); if (tsize != 8 || strcmp(gl_font.string, con_font_name)) { - font_console = Font_LoadFont(con_font_name, tsize, 1, r_font_postprocess_outline.ival); + font_console = Font_LoadFont(con_font_name, tsize, 1, r_font_postprocess_outline.ival, flags); if (!font_console) - font_console = Font_LoadFont("", tsize, 1, r_font_postprocess_outline.ival); + font_console = Font_LoadFont("", tsize, 1, r_font_postprocess_outline.ival, flags); } if (!font_console) font_console = font_default; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index e9b0ce3a9..aa3a4df1b 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -458,6 +458,7 @@ cvar_t gl_texturemode2d = CVARFCD("gl_texturemode2d", "GL_LINEAR", "Specifies how 2d images are sampled. format is a 3-tupple "); cvar_t r_font_linear = CVARF("r_font_linear", "1", CVAR_ARCHIVE); cvar_t r_font_postprocess_outline = CVARFD("r_font_postprocess_outline", "0", 0, "Controls the number of pixels of dark borders to use around fonts."); +cvar_t r_font_postprocess_mono = CVARFD("r_font_postprocess_mono", "0", 0, "Disables anti-aliasing on fonts."); #if defined(HAVE_LEGACY) && defined(AVAIL_FREETYPE) cvar_t dpcompat_smallerfonts = CVARFD("dpcompat_smallerfonts", "0", 0, "Mimics DP's behaviour of using a smaller font size than was actually requested."); @@ -984,6 +985,7 @@ void Renderer_Init(void) Cvar_Register (&gl_texturemode2d, GLRENDEREROPTIONS); Cvar_Register (&r_font_linear, GLRENDEREROPTIONS); Cvar_Register (&r_font_postprocess_outline, GLRENDEREROPTIONS); + Cvar_Register (&r_font_postprocess_mono, GLRENDEREROPTIONS); #if defined(HAVE_LEGACY) && defined(AVAIL_FREETYPE) Cvar_Register (&dpcompat_smallerfonts, GLRENDEREROPTIONS); #endif diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 88e57134f..74da2d66a 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -1279,7 +1279,7 @@ void Draw_TinyString (float x, float y, const qbyte *str) if (!font_tiny) { - font_tiny = Font_LoadFont("gfx/tinyfont", 8, 1, 0); + font_tiny = Font_LoadFont("gfx/tinyfont", 8, 1, 0, 0); if (!font_tiny) return; } diff --git a/engine/client/screen.h b/engine/client/screen.h index d558ac3af..b4ff687a3 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -321,7 +321,8 @@ void Font_Init(void); void Font_Shutdown(void); int Font_RegisterTrackerImage(const char *image); //returns a unicode char value that can be used to embed the char within a line of text. qboolean Font_TrackerValid(unsigned int imid); -struct font_s *Font_LoadFont(const char *fontfilename, float height, float scale, int outline); +struct font_s *Font_LoadFont(const char *fontfilename, float height, float scale, int outline, unsigned int flags); +#define FONT_MONO 1 void Font_Free(struct font_s *f); void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py); void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/ diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 9dea5fb50..7453625ee 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -15,7 +15,7 @@ void Font_Init(void); void Font_Shutdown(void); -struct font_s *Font_LoadFont(const char *fontfilename, float height, float scale, int outline); +struct font_s *Font_LoadFont(const char *fontfilename, float height, float scale, int outline, unsigned int flags); void Font_Free(struct font_s *f); void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py); void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/ @@ -80,6 +80,9 @@ const char *(VARGS *pFT_Error_String) (FT_Error error_code); typedef unsigned int FT_Pixel_Mode; //for consistency even without freetype support. #endif +#ifndef FT_PIXEL_MODE_MONO +#define FT_PIXEL_MODE_MONO 1 +#endif #ifndef FT_PIXEL_MODE_GRAY #define FT_PIXEL_MODE_GRAY 2 #endif @@ -322,6 +325,7 @@ typedef struct font_s unsigned short truecharheight; //what you actually got, for compat with dp's lets-use-the-wrong-size-for-double-padding-between-lines thing. float scale; //some sort of poop short outline; + unsigned int flags; unsigned short faces; fontface_t *face[MAX_FACES]; @@ -721,6 +725,32 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT out += PLANEWIDTH; } } + else if (pixelmode == FT_PIXEL_MODE_MONO) + { //1bit font ( + for (y = -pad; y < 0; y++) + { + for (x = -pad; x < (int)bmw+pad; x++) + out[x].c = BORDERCOLOUR; + out += PLANEWIDTH; + } + for (; y < bmh; y++) + { + for (x = -pad; x < 0; x++) + out[x].c = BORDERCOLOUR; + for (; x < bmw; x++) + out[x].c = (((unsigned char*)data)[x>>3]&(1<<(7-(x&7))))?0xffffffff:0; + for (; x < bmw+pad; x++) + out[x].c = BORDERCOLOUR; + data = (char*)data + pitch; + out += PLANEWIDTH; + } + for (; y < bmh+pad; y++) + { + for (x = -pad; x < (int)bmw+pad; x++) + out[x].c = BORDERCOLOUR; + out += PLANEWIDTH; + } + } else if ((unsigned int)pixelmode == FT_PIXEL_MODE_RGBA_SA) { //rgba source using standard alpha. //(we'll multiply out the alpha for the gpu) @@ -822,9 +852,6 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT if (outline) { - int bytes = (pixelmode == FT_PIXEL_MODE_GRAY)?1:4; - qbyte *alpha = (char*)data + bytes-1 - pitch*bmh; - static int filter_outline; static unsigned char filter_highest[MAXOUTLINE*2+1][MAXOUTLINE*2+1]; if (outline != filter_outline) @@ -837,23 +864,57 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT //expand it to out full(ish) size - alpha -= pitch*outline + bytes*outline; - out = &fontplanes.plane[c->bmx+((int)c->bmy-outline)*PLANEHEIGHT]; - for (y = -outline; y < (int)bmh+outline; y++, out += PLANEWIDTH) - for (x = -outline; x < (int)bmw+outline; x++) - { - int xn, x1 = max(outline-x, 0), x2 = min(2*outline, (int)bmw-1-x+outline); - int yn, y1 = max(outline-y, 0), y2 = min(2*outline, (int)bmh-1-y+outline); - int v, m = out[x].rgba[3]*255; - for (yn = y1; yn <= y2; yn++) - for (xn = x1; xn <= x2; xn++) - { - v = filter_highest[yn][xn] * alpha[(xn+x)*bytes+(yn+y)*pitch]; - m = max(m, v); - } - //out[x].c = 0; - out[x].rgba[3] = m/255; - } + if (pixelmode == FT_PIXEL_MODE_MONO) + { + qbyte *alpha = (char*)data - pitch*bmh; + qbyte a; + int bit; + + alpha -= pitch*outline; + out = &fontplanes.plane[c->bmx+((int)c->bmy-outline)*PLANEHEIGHT]; + for (y = -outline; y < (int)bmh+outline; y++, out += PLANEWIDTH) + for (x = -outline; x < (int)bmw+outline; x++) + { + int xn, x1 = max(outline-x, 0), x2 = min(2*outline, (int)bmw-1-x+outline); + int yn, y1 = max(outline-y, 0), y2 = min(2*outline, (int)bmh-1-y+outline); + int v, m = out[x].rgba[3]*255; + for (yn = y1; yn <= y2; yn++) + for (xn = x1; xn <= x2; xn++) + { + bit = (xn+x)-outline; + a = alpha[(bit>>3)+(yn+y)*pitch]; + a = (a&(1<<(7-(bit&7))))?0xff:0; + + v = filter_highest[yn][xn] * a; + m = max(m, v); + } + //out[x].c = 0; + out[x].rgba[3] = m/255; + } + } + else + { + int bytes = (pixelmode == FT_PIXEL_MODE_GRAY)?1:4; + qbyte *alpha = (char*)data + bytes-1 - pitch*bmh; + + alpha -= pitch*outline + bytes*outline; + out = &fontplanes.plane[c->bmx+((int)c->bmy-outline)*PLANEHEIGHT]; + for (y = -outline; y < (int)bmh+outline; y++, out += PLANEWIDTH) + for (x = -outline; x < (int)bmw+outline; x++) + { + int xn, x1 = max(outline-x, 0), x2 = min(2*outline, (int)bmw-1-x+outline); + int yn, y1 = max(outline-y, 0), y2 = min(2*outline, (int)bmh-1-y+outline); + int v, m = out[x].rgba[3]*255; + for (yn = y1; yn <= y2; yn++) + for (xn = x1; xn <= x2; xn++) + { + v = filter_highest[yn][xn] * alpha[(xn+x)*bytes+(yn+y)*pitch]; + m = max(m, v); + } + //out[x].c = 0; + out[x].rgba[3] = m/255; + } + } c->bmx -= outline; @@ -1317,7 +1378,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) return NULL; //some sort of error. } if (charidx == 0xfffe || pFT_Get_Char_Index(face, charidx)) //ignore glyph 0 (undefined) - if (pFT_Load_Char(face, charidx, FT_LOAD_RENDER|FT_LOAD_COLOR) == 0) + if (pFT_Load_Char(face, charidx, FT_LOAD_RENDER|(((f->flags&FONT_MONO)&&qface->ft.activeheight==qface->ft.actualsize/*FIXME*/)?FT_LOAD_TARGET_MONO:FT_LOAD_TARGET_NORMAL)|FT_LOAD_COLOR) == 0) { FT_GlyphSlot slot; FT_Bitmap *bm; @@ -1349,6 +1410,12 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) Image_ResampleTexture(PTI_L8, (void*)bm->buffer, bm->width, bm->rows, out, nw, nh); c = Font_LoadGlyphData(f, charidx, bm->pixel_mode, out, nw, nh, nw*sizeof(*out)); } + /*else if (bm->pixel_mode == FT_PIXEL_MODE_MONO) + { + unsigned char *out = alloca(nw*nh*sizeof(*out)); + Image_ResampleTexture(PTI_L1, (void*)bm->buffer, bm->width, bm->rows, out, nw, nh); + c = Font_LoadGlyphData(f, charidx, bm->pixel_mode, out, nw, nh, nw*sizeof(*out)); + }*/ else c = NULL; if (c) @@ -2209,7 +2276,7 @@ static qboolean Font_LoadFontLump(font_t *f, const char *facename) //creates a new font object from the given file, with each text row with the given height. //width is implicit and scales with height and choice of font. -struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scale, int outline) +struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scale, int outline, unsigned int flags) { struct font_s *f; int i = 0; @@ -2237,6 +2304,7 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal f->scale = scale; f->charheight = height; f->truecharheight = height; + f->flags = flags; Q_strncpyz(f->name, fontfilename, sizeof(f->name)); switch(M_GameType()) @@ -2454,7 +2522,7 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal } else { - f->alt = Font_LoadFont(aname, vheight, scale, outline); + f->alt = Font_LoadFont(aname, vheight, scale, outline, flags); if (f->alt) { VectorCopy(f->alt->tint, f->alttint);