VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
VM_CL_videoplaying, // #355
-NULL, // #356
-NULL, // #357
+VM_findfont, // #356 float(string fontname) loadfont (DP_GFX_FONTS)
+VM_loadfont, // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS)
NULL, // #358
NULL, // #359
VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
}
dp_font_t;
-#define MAX_FONTS 16
-extern dp_font_t dp_fonts[MAX_FONTS];
-#define FONT_DEFAULT (&dp_fonts[0]) // should be fixed width
-#define FONT_CONSOLE (&dp_fonts[1]) // REALLY should be fixed width (ls!)
-#define FONT_SBAR (&dp_fonts[2]) // must be fixed width
-#define FONT_NOTIFY (&dp_fonts[3]) // free
-#define FONT_CHAT (&dp_fonts[4]) // free
-#define FONT_CENTERPRINT (&dp_fonts[5]) // free
-#define FONT_INFOBAR (&dp_fonts[6]) // free
-#define FONT_MENU (&dp_fonts[7]) // should be fixed width
-#define FONT_USER (&dp_fonts[8]) // userdefined fonts
-#define MAX_USERFONTS (MAX_FONTS - (FONT_USER - dp_fonts))
+typedef struct dp_fonts_s
+{
+ dp_font_t *f;
+ int maxsize;
+}
+dp_fonts_t;
+extern dp_fonts_t dp_fonts;
+
+#define MAX_FONTS 16 // fonts at the start
+#define FONTS_EXPAND 8 // fonts grow when no free slots
+#define FONT_DEFAULT (&dp_fonts.f[0]) // should be fixed width
+#define FONT_CONSOLE (&dp_fonts.f[1]) // REALLY should be fixed width (ls!)
+#define FONT_SBAR (&dp_fonts.f[2]) // must be fixed width
+#define FONT_NOTIFY (&dp_fonts.f[3]) // free
+#define FONT_CHAT (&dp_fonts.f[4]) // free
+#define FONT_CENTERPRINT (&dp_fonts.f[5]) // free
+#define FONT_INFOBAR (&dp_fonts.f[6]) // free
+#define FONT_MENU (&dp_fonts.f[7]) // should be fixed width
+#define FONT_USER(i) (&dp_fonts.f[8+i]) // userdefined fonts
+#define MAX_USERFONTS (dp_fonts.maxsize - 8)
// shared color tag printing constants
#define STRING_COLOR_TAG '^'
void font_shutdown(void)
{
int i;
- for (i = 0; i < MAX_FONTS; ++i)
+ for (i = 0; i < dp_fonts.maxsize; ++i)
{
- if (dp_fonts[i].ft2)
+ if (dp_fonts.f[i].ft2)
{
- Font_UnloadFont(dp_fonts[i].ft2);
- dp_fonts[i].ft2 = NULL;
+ Font_UnloadFont(dp_fonts.f[i].ft2);
+ dp_fonts.f[i].ft2 = NULL;
}
}
Font_CloseLibrary();
Cvar_RegisterVariable(&r_font_size_snapping);
Cvar_RegisterVariable(&r_font_kerning);
Cvar_RegisterVariable(&developer_font);
+
// let's open it at startup already
Font_OpenLibrary();
}
namelen = strlen(name);
+ // try load direct file
memcpy(filename, name, namelen);
- memcpy(filename + namelen, ".ttf", 5);
data = FS_LoadFile(filename, font_mempool, false, &datasize);
+ // try load .ttf
+ if (!data)
+ {
+ memcpy(filename + namelen, ".ttf", 5);
+ data = FS_LoadFile(filename, font_mempool, false, &datasize);
+ }
+ // try load .otf
if (!data)
{
memcpy(filename + namelen, ".otf", 5);
data = FS_LoadFile(filename, font_mempool, false, &datasize);
}
+ // try load .pfb/afm
if (!data)
{
ft2_attachment_t afm;
Font_Attach(font, &afm);
}
}
-
if (!data)
{
// FS_LoadFile being not-quiet should print an error :)
return false;
}
- Con_Printf("Loading font %s face %i...\n", filename, _face);
+ Con_DPrintf("Loading font %s face %i...\n", filename, _face);
status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face);
if (status && _face != 0)
#include "ft2.h"
#include "ft2_fontdefs.h"
-dp_font_t dp_fonts[MAX_FONTS] = {{0}};
+dp_fonts_t dp_fonts;
cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
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)
+void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
{
int i;
float maxwidth, scale;
con_linewidth = -1; // rewrap console in next frame
}
-static dp_font_t *FindFont(const char *title)
+extern cvar_t developer_font;
+dp_font_t *FindFont(const char *title, qboolean allocate_new)
{
int i;
- for(i = 0; i < MAX_FONTS; ++i)
- if(!strcmp(dp_fonts[i].title, title))
- return &dp_fonts[i];
+
+ // find font
+ for(i = 0; i < dp_fonts.maxsize; ++i)
+ if(!strcmp(dp_fonts.f[i].title, title))
+ return &dp_fonts.f[i];
+ // if not found - try allocate
+ if (allocate_new)
+ {
+ // find any font with empty title
+ for(i = 0; i < dp_fonts.maxsize; ++i)
+ {
+ if(!strcmp(dp_fonts.f[i].title, ""))
+ {
+ strlcpy(dp_fonts.f[i].title, title, sizeof(dp_fonts.f[i].title));
+ return &dp_fonts.f[i];
+ }
+ }
+ // if no any 'free' fonts - expand buffer
+ i = dp_fonts.maxsize;
+ dp_fonts.maxsize = dp_fonts.maxsize + FONTS_EXPAND;
+ if (developer_font.integer)
+ Con_Printf("FindFont: enlarging fonts buffer (%i -> %i)\n", i, dp_fonts.maxsize);
+ dp_fonts.f = Mem_Realloc(tempmempool, dp_fonts.f, sizeof(dp_font_t) * dp_fonts.maxsize);
+ // register a font in first expanded slot
+ strlcpy(dp_fonts.f[i].title, title, sizeof(dp_fonts.f[i].title));
+ return &dp_fonts.f[i];
+ }
return NULL;
}
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);
+ for(i = 0; i < dp_fonts.maxsize; ++i)
+ if (dp_fonts.f[i].title[0])
+ Con_Printf(" loadfont %s gfx/tgafile[...] [sizes...]\n", dp_fonts.f[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"
);
return;
}
- f = FindFont(Cmd_Argv(1));
+ f = FindFont(Cmd_Argv(1), true);
if(f == NULL)
{
Con_Printf("font function not found\n");
font_start();
- for(i = 0; i < MAX_FONTS; ++i)
- LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
+ // load default font textures
+ for(i = 0; i < dp_fonts.maxsize; ++i)
+ if (dp_fonts.f[i].title[0])
+ LoadFont(false, va("gfx/font_%s", &dp_fonts.f[i].title), &dp_fonts.f[i]);
// draw the loading screen so people have something to see in the newly opened window
SCR_UpdateLoadingScreen(true);
void GL_Draw_Init (void)
{
int i, j;
+
Cvar_RegisterVariable(&r_font_postprocess_blur);
Cvar_RegisterVariable(&r_font_postprocess_outline);
Cvar_RegisterVariable(&r_font_postprocess_shadow_x);
Cvar_RegisterVariable(&r_textshadow);
Cvar_RegisterVariable(&r_textbrightness);
Cvar_RegisterVariable(&r_textcontrast);
- Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
- R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
+ // allocate fonts storage
+ dp_fonts.maxsize = MAX_FONTS;
+ dp_fonts.f = Mem_Alloc(tempmempool, sizeof(dp_font_t) * dp_fonts.maxsize);
+ memset(dp_fonts.f, 0, sizeof(dp_font_t) * dp_fonts.maxsize);
+
+ // assign starting font names
strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title));
- strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
+ strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath));
strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title));
strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title));
strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title));
strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title));
strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title));
for(i = 0, j = 0; i < MAX_USERFONTS; ++i)
- if(!FONT_USER[i].title[0])
- dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++);
+ if(!FONT_USER(i)->title[0])
+ dpsnprintf(FONT_USER(i)->title, sizeof(FONT_USER(i)->title), "user%d", j++);
+
+ Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
+ R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
}
void _DrawQ_Setup(void)
char *vm_m_extensions =
"BX_WAL_SUPPORT "
"DP_CINEMATIC_DPV "
+"DP_GFX_FONTS "
+"DP_GFX_FONTS_FREETYPE "
+"DP_UTF8 "
"DP_FONT_VARIABLEWIDTH "
"DP_GECKO_SUPPORT "
"DP_MENU_EXTRESPONSEPACKET "
NULL, // #353
NULL, // #354
VM_CL_videoplaying, // #355
-NULL, // #356
-NULL, // #357
+VM_findfont, // #356 float(string fontname) loadfont (DP_GFX_FONTS)
+VM_loadfont, // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS)
NULL, // #358
NULL, // #359
NULL, // #360
if(prog->globaloffsets.drawfont >= 0)
{
int f = (int) PRVM_G_FLOAT(prog->globaloffsets.drawfont);
- if(f < 0 || f >= MAX_FONTS)
+ if(f < 0 || f >= dp_fonts.maxsize)
return FONT_DEFAULT;
- return &dp_fonts[f];
+ return &dp_fonts.f[f];
}
else
return FONT_DEFAULT;
PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth(string, 0, !colors, getdrawfont()) * mult; // 1x1 characters, don't actually draw
*/
+}
+
+/*
+=========
+VM_findfont
+
+float findfont(string s)
+=========
+*/
+
+float getdrawfontnum(const char *fontname)
+{
+ int i;
+
+ for(i = 0; i < dp_fonts.maxsize; ++i)
+ if(!strcmp(dp_fonts.f[i].title, fontname))
+ return i;
+ return -1;
+}
+
+void VM_findfont(void)
+{
+ VM_SAFEPARMCOUNT(1,VM_findfont);
+ PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0));
+}
+
+/*
+=========
+VM_loadfont
+
+float loadfont(string fontname, string fontmaps, string sizes, float slot)
+=========
+*/
+
+dp_font_t *FindFont(const char *title, qboolean allocate_new);
+void LoadFont(qboolean override, const char *name, dp_font_t *fnt);
+void VM_loadfont(void)
+{
+ const char *fontname, *filelist, *sizes, *c, *cm;
+ char mainfont[MAX_QPATH];
+ int i, numsizes;
+ float sz;
+ dp_font_t *f;
+
+ VM_SAFEPARMCOUNTRANGE(3,4,VM_loadfont);
+
+ fontname = PRVM_G_STRING(OFS_PARM0);
+ if (!fontname[0])
+ fontname = "default";
+
+ filelist = PRVM_G_STRING(OFS_PARM1);
+ if (!filelist[0])
+ filelist = "gfx/conchars";
+
+ sizes = PRVM_G_STRING(OFS_PARM2);
+ if (!sizes[0])
+ sizes = "10";
+
+ // find a font
+ f = NULL;
+ if (prog->argc >= 4)
+ {
+ i = PRVM_G_FLOAT(OFS_PARM3);
+ if (i >= 0 && i < dp_fonts.maxsize)
+ {
+ f = &dp_fonts.f[i];
+ strlcpy(f->title, fontname, sizeof(f->title)); // replace name
+ }
+ }
+ if (!f)
+ f = FindFont(fontname, true);
+ if (!f)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return; // something go wrong
+ }
+
+ 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;
+ }
+
+ // handle fallbacks
+ 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;
+ }
+ }
+ // handle sizes
+ for(i = 0; i < MAX_FONT_SIZES; ++i)
+ f->req_sizes[i] = -1;
+ for (numsizes = 0,c = sizes;;)
+ {
+ if (!COM_ParseToken_VM_Tokenize(&c, 0))
+ break;
+ sz = atof(com_token);
+ // detect crap size
+ if (sz < 0.001f || sz > 1000.0f)
+ {
+ VM_Warning("VM_loadfont: crap size %s", com_token);
+ continue;
+ }
+ // check overflow
+ if (numsizes == MAX_FONT_SIZES)
+ {
+ VM_Warning("VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
+ break;
+ }
+ f->req_sizes[numsizes] = sz;
+ numsizes++;
+ }
+
+ // load
+ LoadFont(true, mainfont, f);
+
+ // return index of loaded font
+ PRVM_G_FLOAT(OFS_RETURN) = (f - dp_fonts.f);
}
+
/*
=========
VM_drawpic
void VM_drawresetcliparea(void);
void VM_getimagesize(void);
+void VM_findfont(void);
+void VM_loadfont(void);
+
void VM_makevectors (void);
void VM_vectorvectors (void);
"DP_GFX_QUAKE3MODELTAGS "
"DP_GFX_SKINFILES "
"DP_GFX_SKYBOX "
+"DP_GFX_FONTS "
+"DP_GFX_FONTS_FREETYPE "
+"DP_UTF8 "
+"DP_FONT_VARIABLEWIDTH "
"DP_HALFLIFE_MAP "
"DP_HALFLIFE_MAP_CVAR "
"DP_HALFLIFE_SPRITE "