formed DP_GFX_FONTS/DP_GFX_FONTS_FREETYPE/DP_UTF8 extensions, add loadfont()/findfont...
authorvortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 22 May 2010 22:18:08 +0000 (22:18 +0000)
committervortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 22 May 2010 22:18:08 +0000 (22:18 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10211 d7cf8633-e32d-0410-b094-e92efae38249

clvm_cmds.c
draw.h
ft2.c
gl_draw.c
mvm_cmds.c
prvm_cmds.c
prvm_cmds.h
svvm_cmds.c

index 355f345..20c38fa 100644 (file)
@@ -4347,8 +4347,8 @@ VM_CL_registercmd,                                // #352 void(string cmdname) registercommand (EXT_CSQC)
 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)
diff --git a/draw.h b/draw.h
index e1092f5..538a44b 100644 (file)
--- a/draw.h
+++ b/draw.h
@@ -118,18 +118,26 @@ typedef struct dp_font_s
 }
 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                       '^'
diff --git a/ft2.c b/ft2.c
index ce92935..99dff81 100644 (file)
--- a/ft2.c
+++ b/ft2.c
@@ -251,12 +251,12 @@ void font_start(void)
 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();
@@ -273,6 +273,7 @@ void Font_Init(void)
        Cvar_RegisterVariable(&r_font_size_snapping);
        Cvar_RegisterVariable(&r_font_kerning);
        Cvar_RegisterVariable(&developer_font);
+
        // let's open it at startup already
        Font_OpenLibrary();
 }
@@ -463,14 +464,22 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *setti
 
        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;
@@ -487,13 +496,12 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *setti
                                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)
index 84dfbd8..9a3544f 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #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)"};
@@ -540,7 +540,7 @@ void Draw_FreePic(const char *picname)
 
 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;
@@ -686,12 +686,37 @@ static void LoadFont(qboolean override, const char *name, dp_font_t *fnt)
                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;
 }
 
@@ -732,8 +757,9 @@ static void LoadFont_f(void)
        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"
@@ -745,7 +771,7 @@ static void LoadFont_f(void)
                        );
                return;
        }
-       f = FindFont(Cmd_Argv(1));
+       f = FindFont(Cmd_Argv(1), true);
        if(f == NULL)
        {
                Con_Printf("font function not found\n");
@@ -840,8 +866,10 @@ static void gl_draw_start(void)
 
        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);
@@ -865,6 +893,7 @@ static void gl_draw_newmap(void)
 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);
@@ -875,11 +904,15 @@ void GL_Draw_Init (void)
        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));
@@ -888,8 +921,11 @@ void GL_Draw_Init (void)
        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)
index 9f6f608..9ac5b87 100644 (file)
@@ -12,6 +12,9 @@
 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 "
@@ -1130,8 +1133,8 @@ NULL,                                                                     // #352
 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
index bd6c751..6b8fde3 100644 (file)
@@ -3277,9 +3277,9 @@ dp_font_t *getdrawfont(void)
        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;
@@ -3478,8 +3478,164 @@ void VM_stringwidth(void)
 
        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
index c4f330a..cc9013d 100644 (file)
@@ -359,6 +359,9 @@ void VM_drawsetcliparea(void);
 void VM_drawresetcliparea(void);
 void VM_getimagesize(void);
 
+void VM_findfont(void);
+void VM_loadfont(void);
+
 void VM_makevectors (void);
 void VM_vectorvectors (void);
 
index 625f0ed..a11eb7c 100644 (file)
@@ -57,6 +57,10 @@ char *vm_sv_extensions =
 "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 "