+static float snap_to_pixel_x(float x, float roundUpAt);
+extern int con_linewidth; // to force rewrapping
+static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
+{
+ int i;
+ float maxwidth, scale;
+ char widthfile[MAX_QPATH];
+ char *widthbuf;
+ fs_offset_t widthbufsize;
+
+ if(override || !fnt->texpath[0])
+ {
+ strlcpy(fnt->texpath, name, sizeof(fnt->texpath));
+
+ // load the cvars when the font is FIRST loaded
+ fnt->settings.antialias = r_font_antialias.integer;
+ fnt->settings.hinting = r_font_hinting.integer;
+ fnt->settings.outline = r_font_postprocess_outline.value;
+ fnt->settings.blur = r_font_postprocess_blur.value;
+ fnt->settings.shadowx = r_font_postprocess_shadow_x.value;
+ fnt->settings.shadowy = r_font_postprocess_shadow_y.value;
+ fnt->settings.shadowz = r_font_postprocess_shadow_z.value;
+ }
+
+ if(drawtexturepool == NULL)
+ return; // before gl_draw_start, so will be loaded later
+
+ if(fnt->ft2)
+ {
+ // clear freetype font
+ Font_UnloadFont(fnt->ft2);
+ Mem_Free(fnt->ft2);
+ fnt->ft2 = NULL;
+ }
+
+ if(fnt->req_face != -1)
+ {
+ if(!Font_LoadFont(fnt->texpath, fnt))
+ Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath);
+ }
+
+ fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
+ if(fnt->tex == r_texture_notexture)
+ {
+ for (i = 0; i < MAX_FONT_FALLBACKS; ++i)
+ {
+ if (!fnt->fallbacks[i][0])
+ break;
+ fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex;
+ if(fnt->tex != r_texture_notexture)
+ break;
+ }
+ if(fnt->tex == r_texture_notexture)
+ {
+ fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex;
+ strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile));
+ }
+ else
+ dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->fallbacks[i]);
+ }
+ else
+ dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath);
+
+ // unspecified width == 1 (base width)
+ for(i = 1; i < 256; ++i)
+ fnt->width_of[i] = 1;
+ scale = 1;
+
+ // FIXME load "name.width", if it fails, fill all with 1
+ if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize)))
+ {
+ float extraspacing = 0;
+ const char *p = widthbuf;
+ int ch = 0;
+
+ while(ch < 256)
+ {
+ if(!COM_ParseToken_Simple(&p, false, false))
+ return;
+
+ switch(*com_token)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '+':
+ case '-':
+ case '.':
+ fnt->width_of[ch] = atof(com_token) + extraspacing;
+ if (fnt->ft2)
+ {
+ for (i = 0; i < MAX_FONT_SIZES; ++i)
+ {
+ //Font_MapForIndex(fnt->ft2, i)->width_of[ch] = snap_to_pixel_x(fnt->width_of[ch] * fnt->req_sizes[i], 0.4);
+ ft2_font_map_t *map = Font_MapForIndex(fnt->ft2, i);
+ if (!map)
+ break;
+ map->width_of[ch] = Font_SnapTo(fnt->width_of[ch], 1/map->size);
+ }
+ }
+ ch++;
+ break;
+ default:
+ if(!strcmp(com_token, "extraspacing"))
+ {
+ if(!COM_ParseToken_Simple(&p, false, false))
+ return;
+ extraspacing = atof(com_token);
+ }
+ else if(!strcmp(com_token, "scale"))
+ {
+ if(!COM_ParseToken_Simple(&p, false, false))
+ return;
+ scale = atof(com_token);
+ }
+ else
+ {
+ Con_Printf("Warning: skipped unknown font property %s\n", com_token);
+ if(!COM_ParseToken_Simple(&p, false, false))
+ return;
+ }
+ break;
+ }
+ }
+
+ Mem_Free(widthbuf);
+ }
+
+ maxwidth = fnt->width_of[1];
+ for(i = 2; i < 256; ++i)
+ maxwidth = max(maxwidth, fnt->width_of[i]);
+ fnt->maxwidth = maxwidth;
+
+ // fix up maxwidth for overlap
+ fnt->maxwidth *= scale;
+ fnt->scale = scale;
+
+ if(fnt == FONT_CONSOLE)
+ con_linewidth = -1; // rewrap console in next frame
+}
+
+static dp_font_t *FindFont(const char *title)
+{
+ int i;
+ for(i = 0; i < MAX_FONTS; ++i)
+ if(!strcmp(dp_fonts[i].title, title))
+ return &dp_fonts[i];
+ return NULL;
+}
+
+static float snap_to_pixel_x(float x, float roundUpAt)
+{
+ float pixelpos = x * vid.width / vid_conwidth.value;
+ int snap = (int) pixelpos;
+ if (pixelpos - snap >= roundUpAt) ++snap;
+ return ((float)snap * vid_conwidth.value / vid.width);
+ /*
+ x = (int)(x * vid.width / vid_conwidth.value);
+ x = (x * vid_conwidth.value / vid.width);
+ return x;
+ */
+}
+
+static float snap_to_pixel_y(float y, float roundUpAt)
+{
+ float pixelpos = y * vid.height / vid_conheight.value;
+ int snap = (int) pixelpos;
+ if (pixelpos - snap > roundUpAt) ++snap;
+ return ((float)snap * vid_conheight.value / vid.height);
+ /*
+ y = (int)(y * vid.height / vid_conheight.value);
+ y = (y * vid_conheight.value / vid.height);
+ return y;
+ */
+}
+
+static void LoadFont_f(void)
+{
+ dp_font_t *f;
+ int i;
+ const char *filelist, *c, *cm;
+ float sz;
+ char mainfont[MAX_QPATH];
+
+ if(Cmd_Argc() < 2)
+ {
+ Con_Printf("Available font commands:\n");
+ for(i = 0; i < MAX_FONTS; ++i)
+ Con_Printf(" loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts[i].title);
+ Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n"
+ "can specify multiple fonts and faces\n"
+ "Like this: gfx/vera-sans:2,gfx/fallback:1\n"
+ "to load face 2 of the font gfx/vera-sans and use face 1\n"
+ "of gfx/fallback as fallback font.\n"
+ "You can also specify a list of font sizes to load, like this:\n"
+ "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n"
+ "In many cases, 8 12 16 24 32 should be a good choice.\n"
+ );
+ return;
+ }
+ f = FindFont(Cmd_Argv(1));
+ if(f == NULL)
+ {
+ Con_Printf("font function not found\n");
+ return;
+ }
+
+ if(Cmd_Argc() < 3)
+ filelist = "gfx/conchars";
+ else
+ filelist = Cmd_Argv(2);
+
+ memset(f->fallbacks, 0, sizeof(f->fallbacks));
+ memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
+
+ // first font is handled "normally"
+ c = strchr(filelist, ':');
+ cm = strchr(filelist, ',');
+ if(c && (!cm || c < cm))
+ f->req_face = atoi(c+1);
+ else
+ {
+ f->req_face = 0;
+ c = cm;
+ }
+
+ if(!c || (c - filelist) > MAX_QPATH)
+ strlcpy(mainfont, filelist, sizeof(mainfont));
+ else
+ {
+ memcpy(mainfont, filelist, c - filelist);
+ mainfont[c - filelist] = 0;
+ }
+
+ for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
+ {
+ c = strchr(filelist, ',');
+ if(!c)
+ break;
+ filelist = c + 1;
+ if(!*filelist)
+ break;
+ c = strchr(filelist, ':');
+ cm = strchr(filelist, ',');
+ if(c && (!cm || c < cm))
+ f->fallback_faces[i] = atoi(c+1);
+ else
+ {
+ f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
+ c = cm;
+ }
+ if(!c || (c-filelist) > MAX_QPATH)
+ {
+ strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
+ }
+ else
+ {
+ memcpy(f->fallbacks[i], filelist, c - filelist);
+ f->fallbacks[i][c - filelist] = 0;
+ }
+ }
+
+ // for now: by default load only one size: the default size
+ f->req_sizes[0] = 0;
+ for(i = 1; i < MAX_FONT_SIZES; ++i)
+ f->req_sizes[i] = -1;
+
+ if(Cmd_Argc() >= 3)
+ {
+ for(i = 0; i < Cmd_Argc()-3; ++i)
+ {
+ sz = atof(Cmd_Argv(i+3));
+ if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes
+ f->req_sizes[i] = sz;
+ }
+ }
+
+ LoadFont(true, mainfont, f);
+}
+