diff --git a/basegraph.cpp b/basegraph.cpp index 5bb6634f..409225e5 100644 --- a/basegraph.cpp +++ b/basegraph.cpp @@ -155,9 +155,6 @@ EX int getnext(const char* s, int& i) { } #if CAP_SDLTTF -const int max_font_size = 288; -TTF_Font* font[max_font_size+1]; - void fix_font_size(int& size) { if(size < 1) size = 1; if(size > max_font_size) size = max_font_size; @@ -227,25 +224,36 @@ EX void present_screen() { #if CAP_SDLTTF -#define DEFAULT_FONT "DejaVuSans-Bold.ttf" +EX vector font_filenames = { + "DejaVuSans-Bold.ttf", + "DejaVuSans.ttf", + "cmunss.ttf", + "NotoSans-Regular.ttf", + "OpenDyslexic3-Regular.ttf", + "font.ttf", + "font.otf" + }; + +EX vector> font_names = { + {"DejaVu Sans Bold", ""}, + {"DejaVu Sans", ""}, + {"Computer Modern Sans", ""}, + {"Noto Sans", ""}, + {"OpenDyslexic3-Regular", ""}, + {"TTF font", ""}, + {"OTF font", ""} + }; + +EX int last_font_id = 0; +EX int font_id = 0; #ifdef FONTCONFIG -/** if this is non-empty, find the font using fontconfig */ -EX string font_to_find = DEFAULT_FONT; -#endif +TTF_Font* findfont(int siz) { -/** actual font path */ -EX string fontpath = ISWEB ? "sans-serif" : string(HYPERFONTPATH) + DEFAULT_FONT; - -const string& findfont() { - #ifdef FONTCONFIG - if(font_to_find == "") return fontpath; FcPattern *pat; FcResult result; - if (!FcInit()) { - return fontpath; - } - pat = FcNameParse((FcChar8 *)font_to_find.c_str()); + if (!FcInit()) return nullptr; + pat = FcNameParse((FcChar8 *)cfont->filename.c_str()); FcConfigSubstitute(0, pat, FcMatchPattern); FcDefaultSubstitute(pat); @@ -254,31 +262,33 @@ const string& findfont() { if (match) { FcChar8 *file; if (FcPatternGetString(match, FC_FILE, 0, &file) == FcResultMatch) { - fontpath = (const char *)file; + cfont->filename = (const char *)file; } FcPatternDestroy(match); } FcPatternDestroy(pat); FcFini(); - font_to_find = ""; - if(debugflags & DF_INIT) println(hlog, "fontpath is: ", fontpath); - #endif - return fontpath; + cfont->use_fontconfig = false; + if(debugflags & DF_INIT) println(hlog, "fontpath is: ", cfont->filename); + return TTF_OpenFont(cfont->filename, siz); } +#endif void loadfont(int siz) { fix_font_size(siz); - if(!font[siz]) { - font[siz] = TTF_OpenFont(findfont().c_str(), siz); - // Destination set by ./configure (in the GitHub repository) - #ifdef FONTDESTDIR - if (font[siz] == NULL) { - font[siz] = TTF_OpenFont(FONTDESTDIR, siz); - } + auto& cf = cfont->font[siz]; + if(!cf) { + if(cf == NULL) cf = TTF_OpenFont(find_file(cfont->filename).c_str(), siz); + + #ifdef FONTCONFIG + if(cf == NULL && cfont->use_fontconfig) + cf = find_font_using_fontconfig(siz); #endif - if (font[siz] == NULL) { - printf("error: Font file not found: %s\n", fontpath.c_str()); - exit(1); + + if(cf == NULL) { + printf("error: Font file not found: %s\n", cfont->filename.c_str()); + if(font_id == 0) throw hr_exception("font file not found"); + font_id = 0; set_cfont(); loadfont(siz); } } } @@ -293,7 +303,7 @@ int textwidth(int siz, const string &str) { loadfont(siz); int w, h; - TTF_SizeUTF8(font[siz], str.c_str(), &w, &h); + TTF_SizeUTF8(cfont->font[siz], str.c_str(), &w, &h); // printf("width = %d [%d]\n", w, isize(str)); return w; @@ -435,6 +445,40 @@ EX int next_p2 (int a ) { return rval; } +#if HDR +constexpr int max_glfont_size = 72; +constexpr int max_font_size = 288; + +struct fontdata { + string filename; + #if FONTCONFIG + bool use_fontconfig; + #endif + struct glfont_t* glfont[max_glfont_size+1]; + #if CAP_SDLTTF + TTF_Font* font[max_font_size+1]; + #endif + ~fontdata(); + }; +#endif + +EX map fontdatas; + +EX fontdata *cfont; + +EX fontdata* font_by_name(string fname) { + auto& fd = fontdatas[fname]; + if(fd.filename == "") { + fd.filename = fname; + #if FONTCONFIG + fd.use_fontconfig = true; + #endif + for(int i=0; i<=max_glfont_size; i++) fd.glfont[i] = nullptr; + for(int i=0; i<=max_font_size; i++) fd.font[i] = nullptr; + } + return &fd; + } + #if CAP_GLFONT #define CHARS (128+NUMEXTRA) @@ -450,18 +494,14 @@ struct glfont_t { //GLuint list_base; // Holds The First Display List ID vector chars; }; - -const int max_glfont_size = 72; #endif -EX glfont_t *glfont[max_glfont_size+1]; - typedef Uint16 texturepixel; -#define FONTTEXTURESIZE 2048 +#define FONTTEXTURESIZE 4096 int curx = 0, cury = 0, theight = 0; -texturepixel fontdata[FONTTEXTURESIZE][FONTTEXTURESIZE]; +texturepixel fontpixels[FONTTEXTURESIZE][FONTTEXTURESIZE]; void sdltogl(SDL_Surface *txt, glfont_t& f, int ch) { #if CAP_TABFONT @@ -480,7 +520,7 @@ void sdltogl(SDL_Surface *txt, glfont_t& f, int ch) { theight = max(theight, otheight); for(int j=0; j=otwidth || j>=otheight) ? 0 : (tpix[tpixindex++] * 0x100) | 0xFF; #else @@ -501,17 +541,17 @@ void sdltogl(SDL_Surface *txt, glfont_t& f, int ch) { } EX void init_glfont(int size) { - if(glfont[size]) return; + if(cfont->glfont[size]) return; DEBBI(DF_GRAPH, ("init GL font: ", size)); #if !CAP_TABFONT loadfont(size); - if(!font[size]) return; + if(!cfont->font[size]) return; #endif - glfont[size] = new glfont_t; + cfont->glfont[size] = new glfont_t; - glfont_t& f(*(glfont[size])); + glfont_t& f(*(cfont->glfont[size])); f.chars.resize(CHARS); @@ -527,7 +567,7 @@ EX void init_glfont(int size) { for(int y=0; yfont[siz], str, white); } else { - txt = TTF_RenderUTF8_Blended(font[siz], natchars[ch-128], white); + txt = TTF_RenderUTF8_Blended(cfont->font[siz], natchars[ch-128], white); } if(txt == NULL) continue; #if CAP_CREATEFONT @@ -572,7 +612,7 @@ EX void init_glfont(int size) { glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, FONTTEXTURESIZE, theight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, - fontdata); + fontpixels); for(int ch=0; chglfont[gsiz]) return 0; - glfont_t& f(*glfont[gsiz]); + glfont_t& f(*cfont->glfont[gsiz]); int x = 0; for(int i=0; s[i];) { @@ -628,9 +668,9 @@ bool gl_print(int x, int y, int shift, int size, const char *s, color_t color, i #endif init_glfont(gsiz); - if(!glfont[gsiz]) return false; + if(!cfont->glfont[gsiz]) return false; - glfont_t& f(*glfont[gsiz]); + glfont_t& f(*cfont->glfont[gsiz]); int tsize = 0; @@ -692,9 +732,10 @@ EX void resetGL() { DEBBI(DF_INIT | DF_GRAPH, ("reset GL")) callhooks(hooks_resetGL); #if CAP_GLFONT - for(int i=0; i<=max_glfont_size; i++) if(glfont[i]) { - delete glfont[i]; - glfont[i] = NULL; + for(auto& cf: fontdatas) + for(int i=0; i<=max_glfont_size; i++) if(cf.second.glfont[i]) { + delete cf.second.glfont[i]; + cf.second.glfont[i] = NULL; } #endif #if MAXMDIM >= 4 @@ -819,7 +860,7 @@ EX bool displaystr(int x, int y, int shift, int size, const char *str, color_t c fix_font_size(size); loadfont(size); - SDL_Surface *txt = ((vid.antialias & AA_FONT)?TTF_RenderUTF8_Blended:TTF_RenderUTF8_Solid)(font[size], str, col); + SDL_Surface *txt = ((vid.antialias & AA_FONT)?TTF_RenderUTF8_Blended:TTF_RenderUTF8_Solid)(cfont->font[size], str, col); if(txt == NULL) return false; @@ -1436,22 +1477,26 @@ EX int SDL_Init1(Uint32 flags) { } #endif +EX void set_cfont() { + cfont = font_by_name(font_filenames[last_font_id = font_id]); + } + EX void init_font() { #if CAP_SDLTTF if(TTF_Init() != 0) { printf("Failed to initialize TTF.\n"); exit(2); } + set_cfont(); #endif } -EX void close_font() { +fontdata::~fontdata() { #if CAP_SDLTTF for(int i=0; i<=max_font_size; i++) if(font[i]) { TTF_CloseFont(font[i]); font[i] = nullptr; } - TTF_Quit(); #endif #if CAL_GLFONT for(int i=0; i<=max_glfont_size; i++) if(glfont[i]) { @@ -1461,6 +1506,11 @@ EX void close_font() { #endif } +EX void close_font() { + fontdatas.clear(); + TTF_Quit(); + } + EX void init_graph() { #if CAP_SDL if (SDL_Init1(SDL_INIT_VIDEO) == -1) diff --git a/commandline.cpp b/commandline.cpp index 13c0eddb..55da86f4 100644 --- a/commandline.cpp +++ b/commandline.cpp @@ -172,14 +172,7 @@ int arg::readCommon() { else if(argis("-nogui")) { PHASE(1); noGUI = true; } #ifndef EMSCRIPTEN #if CAP_SDL - else if(argis("-font")) { PHASE(1); shift(); fontpath = args(); - #ifdef FONTCONFIG - font_to_find = ""; - #endif - } -#ifdef FONTCONFIG - else if(argis("-find-font")) { PHASE(1); shift(); font_to_find = args(); } -#endif + else if(argis("-font")) { PHASE(1); shift(); font_id = isize(font_filenames); font_filenames.push_back(args()); font_names.push_back({args(), "commandline"}); } #endif #endif diff --git a/config.cpp b/config.cpp index 847bb7fa..aba4e02f 100644 --- a/config.cpp +++ b/config.cpp @@ -1013,6 +1013,16 @@ EX purehookset hooks_configfile; EX ld mapfontscale = 100; +EX void font_reaction() { + if(among(font_id, 5, 6)) { + int fid = font_id; + font_id = last_font_id; + dialog::openFileDialog(font_filenames[fid], XLAT("font to use:"), fid == 5 ? ".ttf" : ".otf", [fid] () { + font_id = fid; return true; + }); + } + } + EX void initConfig() { // basic config @@ -1099,6 +1109,11 @@ EX void initConfig() { initcs(vid.cs); paramset(vid.cs, "single"); param_b(vid.samegender, "princess choice", false); param_i(vid.language, "language", -1); + param_enum(font_id, "font_id", 0) + ->editable(font_names, "select font", 'f') + ->manual_reaction = font_reaction; + param_str(font_filenames[5], "ttf_font"); + param_str(font_filenames[6], "otf_font"); param_b(vid.drawmousecircle, "mouse circle", ISMOBILE || ISPANDORA); param_b(vid.revcontrol, "reverse control", false); #if CAP_AUDIO @@ -2424,6 +2439,8 @@ EX void configureInterface() { dialog::add_action_push(selectLanguageScreen); #endif + add_edit(font_id); + dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g'); dialog::add_action_push(showCustomizeChar); if(getcstat == 'g') mouseovers = XLAT("Affects looks and grammar"); diff --git a/drawing.cpp b/drawing.cpp index 7774c497..96421dc3 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -2872,7 +2872,7 @@ EX hyperpoint default_pointfunction(ld x, ld y) { #if !CAP_EXTFONT EX void write_in_space(const shiftmatrix& V, int fsize, double size, const string& s, color_t col, int frame IS(0), int align IS(8), PPR prio IS(PPR::TEXT), pointfunction pf IS(default_pointfunction)) { init_glfont(fsize); - glfont_t& f(*(glfont[fsize])); + glfont_t& f(*(cfont->glfont[fsize])); finf.texture_id = f.texture; int fstart = isize(finf.tvertices); diff --git a/graph.cpp b/graph.cpp index a335294e..9e0009e2 100644 --- a/graph.cpp +++ b/graph.cpp @@ -5600,6 +5600,7 @@ EX void calcparam() { ld fov = vid.fov * degree / 2; cd->tanfov = sin(fov) / (cos(fov) + get_stereo_param()); + set_cfont(); callhooks(hooks_calcparam); reset_projection(); }