]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
Replacing old font codepage-map loader with a loader which allocates space for glyphs...
authorWolfgang (Blub) Bumiller <blub@speed.at>
Wed, 2 Nov 2011 14:46:24 +0000 (15:46 +0100)
committerWolfgang Bumiller <wolfgang.linux@bumiller.com>
Mon, 30 Apr 2012 18:59:35 +0000 (20:59 +0200)
ft2.c
ft2.h
ft2_fontdefs.h
gl_draw.c
gl_textures.c
model_brush.c
model_shared.c
model_shared.h

diff --git a/ft2.c b/ft2.c
index e1c2fe491afef56fc74a7e6f9eecee842d87dde5..7c869c69c0878ff3ab9d054010c47be6dddc161a 100644 (file)
--- a/ft2.c
+++ b/ft2.c
@@ -142,6 +142,11 @@ static mempool_t *font_mempool= NULL;
 /// FreeType library handle
 static FT_Library font_ft2lib = NULL;
 
+/// GlyphTex texture list
+static ft2_glyphtex_t *font_glyphtex_start = NULL;
+static ft2_glyphtex_t *font_glyphtex_end = NULL;
+static int font_glyphtex_counter = 0;
+
 #define POSTPROCESS_MAXRADIUS 8
 typedef struct
 {
@@ -313,6 +318,8 @@ void font_start(void)
                Font_CloseLibrary();
                return;
        }
+
+       font_glyphtex_start = font_glyphtex_end = NULL;
 }
 
 void font_shutdown(void)
@@ -363,6 +370,88 @@ ft2_font_t *Font_Alloc(void)
        return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
 }
 
+ft2_glyphtex_t *Font_New_GlyphTex(int width, int height)
+{
+       int bytesPerPixel = 4;
+       int tp;
+       char vabuf[512];
+       unsigned char *gtdata;
+       int gtpitch;
+
+       ft2_glyphtex_t *gt = (ft2_glyphtex_t *)Mem_Alloc(font_mempool, sizeof(ft2_glyphtex_t));
+       if (!font_glyphtex_start)
+               font_glyphtex_start = gt;
+       if (font_glyphtex_end) {
+               font_glyphtex_end->next = gt;
+               gt->prev = font_glyphtex_end;
+               font_glyphtex_end = gt;
+       } else {
+               font_glyphtex_end = gt;
+       }
+
+       if (r_font_use_alpha_textures.integer)
+               bytesPerPixel = 1;
+
+       gt->width = width;
+       gt->height = height;
+       gt->texflags = TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0);
+       gt->bytesPerPixel = bytesPerPixel;
+       gtpitch = width * bytesPerPixel;
+       gt->tex = NULL;
+       gtdata = (unsigned char*)Mem_Alloc(font_mempool, width * height * bytesPerPixel);
+       //memset(gt->data, 0, width * height * bytesPerPixel);
+       // Initialize as white texture with zero alpha
+       tp = 0;
+       while (tp < height*gtpitch)
+       {
+               if (bytesPerPixel == 4)
+               {
+                       gtdata[tp++] = 0xFF;
+                       gtdata[tp++] = 0xFF;
+                       gtdata[tp++] = 0xFF;
+               }
+               gtdata[tp++] = 0x00;
+       }
+       // now load the texture
+       gt->tex = R_LoadTexture2D(drawtexturepool, va(vabuf, sizeof(vabuf), "*font-%i", font_glyphtex_counter),
+                                 gt->width, gt->height, gtdata,
+                                 (r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA),
+                                 gt->texflags, -1, NULL);
+       Mem_Free(gtdata);
+
+       Mod_AllocLightmap_Init(&gt->blockstate, width, height, font_mempool);
+
+       gt->glyph_count = 0;
+       //gt->lastusedframe = 0;
+
+       gt->first_glyph = gt->last_glyph = NULL;
+
+       ++font_glyphtex_counter;
+       Con_Printf("Glyphtextures: %i\n", font_glyphtex_counter);
+       return gt;
+}
+
+void Font_Free_GlyphTex(ft2_glyphtex_t *gt);
+void Font_Free_GlyphTex(ft2_glyphtex_t *gt)
+{
+       ft2_glyphtex_t *prev = gt->prev;
+       ft2_glyphtex_t *next = gt->next;
+
+       if (prev)
+               prev->next = next;
+       if (next)
+               next->prev = prev;
+
+       //Mem_Free(gt->data);
+       Mod_AllocLightmap_Free(&gt->blockstate);
+
+       // FIXME: Go through glyphs now
+
+       R_FreeTexture(gt->tex);
+       gt->tex = NULL;
+       Mem_Free(gt);
+}
+
 static qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
 {
        ft2_attachment_t *na;
@@ -405,7 +494,8 @@ float Font_SnapTo(float val, float snapwidth)
 }
 
 static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font);
-static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
+static void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b);
+//static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only);
 qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
 {
        int s, count, i;
@@ -469,7 +559,10 @@ qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
                count = 0;
                for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
                {
-                       if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
+                       fb->req_sizes[s] = Font_VirtualToRealSize(dpfnt->req_sizes[s]);
+                       if (fb->req_sizes[s] < 2 || fb->req_sizes[s] > 200) {
+                               // Bogus size check needs to be done here already
+                       } else
                                ++count;
                }
                if (!count)
@@ -496,8 +589,25 @@ qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
        count = 0;
        for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
        {
-               if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
+               int gpad_l, gpad_r, gpad_t, gpad_b;
+               ft2_font_size_t *fsize = &ft2->font_sizes[s];
+               ft2->req_sizes[s] = Font_VirtualToRealSize(dpfnt->req_sizes[s]);
+               if (ft2->req_sizes[s] < 2 || ft2->req_sizes[s] > 200) {
+                       // Bogus size check needs to be done here already
+               } else
                        ++count;
+
+               // Fill fontsize here now, since we have no Font_LoadSize anymore
+               Font_Postprocess(ft2, NULL, 0, 4, fsize->size*2, fsize->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
+               fsize->size = ft2->req_sizes[s];
+               fsize->sfx = (1.0/64.0)/(double)fsize->size;
+               fsize->sfy = (1.0/64.0)/(double)fsize->size;
+               fsize->glyphSize = fsize->size * 2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
+               /* Not required anymore, all textures are 1024x1024 for now
+               if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
+                       fsize->glyphSize = CeilPowerOf2(fsize->glyphSize);
+               */
+               fsize->intSize = -1;
        }
        if (!count)
        {
@@ -790,7 +900,9 @@ static void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitc
 }
 
 static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size);
-static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
+//static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap);
+#if 0
+// DEPRECATED:
 static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
 {
        int map_index;
@@ -877,6 +989,7 @@ static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
        }
        return true;
 }
+#endif
 
 int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
 {
@@ -886,7 +999,6 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
        int matchsize = -10000;
        int m;
        float fsize_x, fsize_y;
-       ft2_font_map_t **maps = font->font_maps;
 
        fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
        if(outw && *outw)
@@ -909,15 +1021,15 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
 
        for (m = 0; m < MAX_FONT_SIZES; ++m)
        {
-               if (!maps[m])
+               if (font->req_sizes[m] < 1)
                        continue;
                // "round up" to the bigger size if two equally-valued matches exist
-               nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y));
-               if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
+               nval = 0.5 * (fabs(font->font_sizes[m].size - fsize_x) + fabs(font->font_sizes[m].size - fsize_y));
+               if (match == -1 || nval < value || (nval == value && matchsize < font->font_sizes[m].size))
                {
                        value = nval;
                        match = m;
-                       matchsize = maps[m]->size;
+                       matchsize = font->font_sizes[m].size;
                        if (value == 0) // there is no better match
                                break;
                }
@@ -925,18 +1037,21 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
        if (value <= r_font_size_snapping.value)
        {
                // do NOT keep the aspect for perfect rendering
-               if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
-               if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
+               if (outh) *outh = font->font_sizes[match].size * vid_conheight.value / vid.height;
+               if (outw) *outw = font->font_sizes[match].size * vid_conwidth.value / vid.width;
        }
        return match;
 }
 
+#if 0
+// DEPRECATED:
 ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index)
 {
        if (index < 0 || index >= MAX_FONT_SIZES)
                return NULL;
        return font->font_maps[index];
 }
+#endif
 
 static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
 {
@@ -964,6 +1079,16 @@ static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
        return true;
 }
 
+qboolean Font_GetKerning(ft2_font_t *font, int size_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
+{
+       // FIXME: Currently dummied because we are focusing on glyph loading
+       if (outx) *outx = 0;
+       if (outy) *outy = 0;
+       return false;
+}
+
+#if 0
+// DEPRECATED:
 qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy)
 {
        ft2_font_map_t *fmap;
@@ -1026,7 +1151,9 @@ qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left,
 {
        return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy);
 }
+#endif
 
+/*
 static void UnloadMapRec(ft2_font_map_t *map)
 {
        if (map->pic)
@@ -1038,6 +1165,7 @@ static void UnloadMapRec(ft2_font_map_t *map)
                UnloadMapRec(map->next);
        Mem_Free(map);
 }
+*/
 
 void Font_UnloadFont(ft2_font_t *font)
 {
@@ -1057,6 +1185,7 @@ void Font_UnloadFont(ft2_font_t *font)
                font->attachmentcount = 0;
                font->attachments = NULL;
        }
+       /*
        for (i = 0; i < MAX_FONT_SIZES; ++i)
        {
                if (font->font_maps[i])
@@ -1065,6 +1194,7 @@ void Font_UnloadFont(ft2_font_t *font)
                        font->font_maps[i] = NULL;
                }
        }
+       */
        if (ft2_dll)
        {
                if (font->face)
@@ -1100,6 +1230,465 @@ static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
        }
 }
 
+static glyph_t* Font_Glyph_Find(ft2_font_size_t *fsize, Uchar ch)
+{
+       ft2_glyph_tree_t *tree;
+       unsigned int i, idx;
+
+       if (ch < 256)
+               return fsize->main_glyphs[ch];
+
+       tree = &fsize->glyphtree;
+       for (i = 0; i < (2 * sizeof(Uchar) - 1); ++i) {
+               idx = (ch & 0x0F);
+               if (!tree->next[idx])
+                       return NULL;
+               tree = tree->next[idx];
+               ch >>= 4;
+       }
+
+       idx = (ch & 0x0F);
+       return tree->next[idx]->endglyph;
+}
+
+static void Font_Glyph_Insert(ft2_font_size_t *fsize, Uchar ch, glyph_t *glyph)
+{
+       ft2_glyph_tree_t *tree;
+       unsigned int i, idx;
+       if (ch < 256)
+       {
+               fsize->main_glyphs[ch] = glyph;
+               return;
+       }
+
+       tree = &fsize->glyphtree;
+       for (i = 0; i < (2 * sizeof(Uchar)); ++i) {
+               idx = (ch & 0x0F);
+               if (!tree->next[idx]) {
+                       tree->next[idx] = (ft2_glyph_tree_t*)Mem_Alloc(font_mempool, sizeof(*tree));
+                       memset(tree->next[idx], 0, sizeof(*(tree->next[idx])));
+               }
+               tree = tree->next[idx];
+               ch >>= 4;
+       }
+       tree->endglyph = glyph;
+       return;
+}
+
+static void Font_Glyph_Free(glyph_t *glyph);
+static void Font_GlyphTree_Free(ft2_glyph_tree_t *tree)
+{
+       unsigned int i;
+       for (i = 0; i < sizeof(tree->next) / sizeof(tree->next[0]); ++i)
+       {
+               if (tree->next[i])
+                       Font_GlyphTree_Free(tree->next[i]);
+       }
+       if (tree->endglyph)
+       {
+               Font_Glyph_Free(tree->endglyph);
+       }
+       Mem_Free(tree);
+}
+
+static void Font_Glyph_Free(glyph_t *glyph)
+{
+       // FIXME: tell the glyphtexture that this glyph is now gone...
+       Mem_Free(glyph);
+}
+
+glyph_t* Font_GetGlyph(ft2_font_t *font, int sizeindex, float _w, float _h, Uchar _ch)
+{
+       // Currently we only care about size_index rather than w, h
+       // In the future we might allow a cvar to allocat glyphs for any size directly, but
+       // this would be dangerous unless we also free glyph frequently.
+       // Also it's a bad idea when there's scaling involved.
+       // ... Unless it all performs very well ...
+
+       //assert(sizeindex >= 0 && sizeindex < MAX_FONT_SIZES && "Font_GetGlyph: Invalid size index: out of array bounds!");
+
+       ft2_font_size_t *fsize;
+       glyph_t         *glyph;
+
+       ft2_font_t      *usefont;
+
+       ft2_glyphtex_t  *glyphtex = font_glyphtex_end;
+       int              status;
+       FT_ULong         ch;
+       FT_Int32         load_flags;
+       int              gpad_l, gpad_r, gpad_t, gpad_b;
+       unsigned char   *data;
+       int              gR, gC; // glyph position: row, column - now x, y actually
+       FT_Face          fontface;
+
+       int              allocw = 0, alloch = 0;
+       int              tp;
+
+       // Freetype vars:
+       FT_ULong         ft_glyphIndex;
+       int              w, h, x, y;
+       FT_GlyphSlot     ft_glyph;
+       FT_Bitmap       *bmp;
+       unsigned char   *imagedata = NULL, *dst, *src;
+       FT_Face          ft_face;
+       int              pad_l, pad_r, pad_t, pad_b;
+
+       // info copied from glyphtex later on:
+       int bytesPerPixel;
+       int pitch;
+
+       // In case the first glyphtex texture was not yet loaded, load it.
+       if (!glyphtex) {
+               glyphtex = Font_New_GlyphTex(FONT_GLYPHTEX_WIDTH, FONT_GLYPHTEX_HEIGHT);
+       }
+
+       if (sizeindex < 0 || sizeindex > MAX_FONT_SIZES) {
+               Con_Printf("ERROR: out of bounds size-index in GetGlyph: %i\n", sizeindex);
+               return NULL;
+       }
+
+       fsize = &font->font_sizes[sizeindex];
+
+       if ( (glyph = Font_Glyph_Find(fsize, _ch)) ) {
+               return glyph;
+       }
+
+       // Glyph is new: create it
+       ch = (FT_ULong)_ch;
+
+       // NOTE: When rendering: r_font_use_alpha_textures is NOT to be used, but instead
+       // the texture's alpha-texture value.
+       // Also: We might want to actually finish alpha-textures for fonts...
+       // We'd require a shader change to make proper use of it tho: to treat that single alpha value and assume
+       // the color to be white + quakecolor(^x)
+
+       if (font->image_font)
+               fontface = (FT_Face)font->next->face;
+       else
+               fontface = (FT_Face)font->face;
+
+       switch(font->settings->antialias)
+       {
+               case 0:
+                       switch(font->settings->hinting)
+                       {
+                               case 0:
+                                       load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
+                                       break;
+                               case 1:
+                               case 2:
+                                       load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
+                                       break;
+                               default:
+                               case 3:
+                                       load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME;
+                                       break;
+                       }
+                       break;
+               default:
+               case 1:
+                       switch(font->settings->hinting)
+                       {
+                               case 0:
+                                       load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL;
+                                       break;
+                               case 1:
+                                       load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
+                                       break;
+                               case 2:
+                                       load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
+                                       break;
+                               default:
+                               case 3:
+                                       load_flags = FT_LOAD_TARGET_NORMAL;
+                                       break;
+                       }
+                       break;
+       }
+
+       if (font->image_font && fsize->intSize < 0)
+               fsize->intSize = fsize->size;
+
+       if (fsize->intSize < 0)
+       {
+               if ((fsize->intSize = Font_SearchSize(font, fontface, fsize->size)) <= 0) {
+                       return NULL;
+               }
+               Con_DPrintf("Using size: %f for requested size %f\n", fsize->intSize, fsize->size);
+       }
+
+       if (!font->image_font && !Font_SetSize(font, fsize->intSize, fsize->intSize))
+       {
+               Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, fsize->size);
+               return NULL;
+       }
+
+       glyph = (glyph_t*)Mem_Alloc(font_mempool, sizeof(glyph_t));
+       if (!glyph)
+       {
+               Con_Printf("ERROR: Out of memory when loading glyph %u for %s\n", (unsigned int)_ch, font->name);
+               return NULL;
+       }
+
+       // Freetype loading
+       ft_face = (FT_Face)font->face;
+       usefont = NULL;
+       if (font->image_font && ch <= 0xFF && img_fontmap[ch])
+       {
+               glyph->image = true;
+               return glyph;
+       }
+
+       ft_glyphIndex = qFT_Get_Char_Index(ft_face, ch);
+       if (ft_glyphIndex == 0)
+       {
+               // by convention, 0 is the "missing-glyph"-glyph
+               // try to load from a fallback font
+               for (usefont = font->next; usefont != NULL; usefont = usefont->next)
+               {
+                       if (!Font_SetSize(usefont, fsize->intSize, fsize->intSize))
+                               continue;
+                       ft_face = (FT_Face)usefont->face;
+                       ft_glyphIndex = qFT_Get_Char_Index(ft_face, ch);
+                       if (ft_glyphIndex == 0)
+                               continue;
+                       status = qFT_Load_Glyph(ft_face, ft_glyphIndex, FT_LOAD_RENDER | load_flags);
+                       if (status)
+                               continue;
+                       break;
+               }
+               if (!usefont)
+               {
+                       // Use the missing-glyph glyph
+                       ft_face = (FT_Face)font->face;
+                       ft_glyphIndex = 0;
+               }
+       }
+
+       if (!usefont)
+       {
+               usefont = font;
+               ft_face = (FT_Face)font->face;
+               status = qFT_Load_Glyph(ft_face, ft_glyphIndex, FT_LOAD_RENDER | load_flags);
+               if (status)
+               {
+                       Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
+                       Mem_Free(glyph);
+                       return NULL;
+               }
+       }
+
+       Font_Postprocess(font, NULL, 0, glyphtex->bytesPerPixel, fsize->size*2, fsize->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
+
+       //pitch = glyphtex->pitch;
+       //data = glyphtex->data;
+
+       ft_glyph = ft_face->glyph;
+       bmp = &ft_glyph->bitmap;
+
+       w = bmp->width;
+       h = bmp->rows;
+
+       if (w > (fsize->glyphSize - gpad_l - gpad_r) || h > (fsize->glyphSize - gpad_t - gpad_b))
+       {
+               Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g, %i x %i\n", (unsigned long)ch, font->name, fsize->size, w, h);
+               if (w > fsize->glyphSize)
+                       w = fsize->glyphSize - gpad_l - gpad_r;
+               if (h > fsize->glyphSize)
+                       h = fsize->glyphSize;
+       }
+
+       // Allocate a block on the glyph texture:
+       allocw = w + gpad_l + gpad_r;
+       alloch = h + gpad_t + gpad_b;
+       if (allocw < w || alloch < h) {
+               Con_Printf("ERROR: Glyph bitmap is bigger than expected: %i < %i, %i < %i\n", allocw, w, alloch, h);
+               Mem_Free(glyph);
+               return NULL;
+       }
+       if (!Mod_AllocLightmap_Block(&glyphtex->blockstate, allocw, alloch, &gC, &gR))
+       {
+               // Texture full: make new one
+               glyphtex = Font_New_GlyphTex(FONT_GLYPHTEX_WIDTH, FONT_GLYPHTEX_HEIGHT);
+               if (!Mod_AllocLightmap_Block(&glyphtex->blockstate, allocw, alloch, &gC, &gR))
+               {
+                       Con_Printf("ERROR: Glyph %lu is too big to fit on a single texture, this is a bogus size. Font %s, size %g, %i x %i\n",
+                                  (unsigned long)ch, font->name, fsize->size, w, h);
+                       Mem_Free(glyph);
+                       return NULL;
+               }
+       }
+
+       glyph->glyphtex = glyphtex;
+       glyph->tex = glyphtex->tex;
+
+       // Glyph is rendered and we have space allocated on a glyph-texture.
+       // We're good to go, ready for postprocessing and the rest.
+
+       bytesPerPixel = glyphtex->bytesPerPixel;
+       //pitch = glyphtex->pitch;
+       //imagedata = glyphtex->data + gR * pitch + gC * bytesPerPixel;
+       pitch = glyphtex->bytesPerPixel * allocw;
+       data = (unsigned char *)Mem_Alloc(font_mempool, alloch * pitch);
+       imagedata = data + gpad_t * pitch + gpad_l * bytesPerPixel;
+
+       tp = 0;
+       while (tp < pitch * alloch)
+       {
+               if (bytesPerPixel == 4) {
+                       data[tp++] = 0xFF;
+                       data[tp++] = 0xFF;
+                       data[tp++] = 0xFF;
+               }
+               data[tp++] = 0x00;
+       }
+
+       switch (bmp->pixel_mode)
+       {
+       case FT_PIXEL_MODE_MONO:
+               if (developer_font.integer)
+                       Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
+               break;
+       case FT_PIXEL_MODE_GRAY2:
+               if (developer_font.integer)
+                       Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
+               break;
+       case FT_PIXEL_MODE_GRAY4:
+               if (developer_font.integer)
+                       Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
+               break;
+       case FT_PIXEL_MODE_GRAY:
+               if (developer_font.integer)
+                       Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
+               break;
+       default:
+               if (developer_font.integer)
+                       Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
+               Mem_Free(data);
+               Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, fsize->size, bmp->pixel_mode);
+               Mem_Free(glyph);
+               return false;
+       }
+       for (y = 0; y < h; ++y)
+       {
+               dst = imagedata + y * pitch;
+               src = bmp->buffer + y * bmp->pitch;
+
+               switch (bmp->pixel_mode)
+               {
+               case FT_PIXEL_MODE_MONO:
+                       dst += bytesPerPixel - 1; // shift to alpha byte
+                       for (x = 0; x < bmp->width; x += 8)
+                       {
+                               unsigned char ch = *src++;
+                               *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
+                               *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
+                       }
+                       break;
+               case FT_PIXEL_MODE_GRAY2:
+                       dst += bytesPerPixel - 1; // shift to alpha byte
+                       for (x = 0; x < bmp->width; x += 4)
+                       {
+                               unsigned char ch = *src++;
+                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                       }
+                       break;
+               case FT_PIXEL_MODE_GRAY4:
+                       dst += bytesPerPixel - 1; // shift to alpha byte
+                       for (x = 0; x < bmp->width; x += 2)
+                       {
+                               unsigned char ch = *src++;
+                               *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
+                               *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
+                       }
+                       break;
+               case FT_PIXEL_MODE_GRAY:
+                       // in this case pitch should equal width
+                       for (tp = 0; tp < bmp->pitch; ++tp)
+                               dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
+
+                       //memcpy((void*)dst, (void*)src, bmp->pitch);
+                       //dst += bmp->pitch;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       pad_l = gpad_l;
+       pad_r = gpad_r;
+       pad_t = gpad_t;
+       pad_b = gpad_b;
+       Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
+
+       R_UpdateTexture(glyphtex->tex, data, gC, gR, 0, allocw, alloch, 8 * bytesPerPixel);
+       Mem_Free(data);
+
+       R_SaveTextureTGAFile(glyphtex->tex, "font-texture.tga", true);
+
+       glyph->image = false;
+       {
+               // old way
+               // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
+
+               double bearingX = (ft_glyph->metrics.horiBearingX / 64.0) / fsize->size;
+               //double bearingY = (ft_glyph->metrics.horiBearingY >> 6) / fsize->size;
+               double advance = (ft_glyph->advance.x / 64.0) / fsize->size;
+               //double mWidth = (ft_glyph->metrics.width >> 6) / fsize->size;
+               //double mHeight = (ft_glyph->metrics.height >> 6) / fsize->size;
+
+               glyph->txmin = ( (double)(gC /* fsize->glyphSize*/) + (double)(gpad_l - pad_l) ) / ( (double)glyphtex->width );
+               glyph->txmax = glyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( glyphtex->width );
+               glyph->tymin = ( (double)(gR /* fsize->glyphSize*/) + (double)(gpad_r - pad_r) ) / ( (double)glyphtex->height );
+               glyph->tymax = glyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)glyphtex->height );
+               //Con_Printf("%f %f %f %f (%i - %i and %i - %i) %c\n", glyph->txmin, glyph->txmax, glyph->tymin, glyph->tymax, gpad_l, pad_l, gpad_r, pad_r, (char)_ch);
+               //glyph->vxmin = bearingX;
+               //glyph->vxmax = bearingX + mWidth;
+               glyph->vxmin = (ft_glyph->bitmap_left - pad_l) / fsize->size;
+               glyph->vxmax = glyph->vxmin + (bmp->width + pad_l + pad_r) / fsize->size; // don't ask
+               //glyph->vymin = -bearingY;
+               //glyph->vymax = mHeight - bearingY;
+               glyph->vymin = (-ft_glyph->bitmap_top - pad_t) / fsize->size;
+               glyph->vymax = glyph->vymin + (bmp->rows + pad_t + pad_b) / fsize->size;
+               //Con_Printf("dpi = %f %f (%f %d) %d %d\n", bmp->width / (glyph->vxmax - glyph->vxmin), bmp->rows / (glyph->vymax - glyph->vymin), map->size, map->ft_glyphSize, (int)fontface->size->metrics.x_ppem, (int)fontface->size->metrics.y_ppem);
+               //glyph->advance_x = advance * usefont->size;
+               //glyph->advance_x = advance;
+               glyph->advance_x = Font_SnapTo(advance, 1 / fsize->size);
+               glyph->advance_y = 0;
+
+               if (developer_font.integer)
+               {
+                       Con_DPrintf("glyphinfo:   glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
+                       Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, fsize->sfx, (unsigned long)ft_glyph->metrics.horiBearingX);
+                       if (ch >= 32 && ch <= 128)
+                               Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
+                       Con_DPrintf("glyphinfo:   Vertex info:\n");
+                       Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", glyph->vxmin, glyph->vxmax);
+                       Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", glyph->vymin, glyph->vymax);
+                       Con_DPrintf("glyphinfo:   Texture info:\n");
+                       Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", glyph->txmin, glyph->txmax);
+                       Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", glyph->tymin, glyph->tymax);
+                       Con_DPrintf("glyphinfo:   Advance: %f, %f\n", glyph->advance_x, glyph->advance_y);
+               }
+       }
+
+       // Insert the glyph into the glyph tree
+       Font_Glyph_Insert(fsize, _ch, glyph);
+
+       return glyph;
+}
+
+#if 0
+// DEPRECATED:
 static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap)
 {
        char map_identifier[MAX_QPATH];
@@ -1572,7 +2161,10 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                *outmap = map;
        return true;
 }
+#endif
 
+#if 0
+// DEPRECATED:
 qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap)
 {
        if (map_index < 0 || map_index >= MAX_FONT_SIZES)
@@ -1591,3 +2183,4 @@ ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
                return NULL;
        return start;
 }
+#endif
diff --git a/ft2.h b/ft2.h
index e8110a72916263c87742039a6d410fe8e0d59fba..8b4f3498a2eb37fa2fd552d52f4199cd13b5bd19 100644 (file)
--- a/ft2.h
+++ b/ft2.h
@@ -20,6 +20,7 @@
  *     Contains the non-FreeType2 version of characters.
  */
 
+typedef struct ft2_glyphtex_s ft2_glyphtex_t;
 typedef struct ft2_font_map_s ft2_font_map_t;
 typedef struct ft2_attachment_s ft2_attachment_t;
 #define ft2_oldstyle_map ((ft2_font_map_t*)-1)
@@ -30,6 +31,34 @@ typedef struct ft2_kerning_s
        ft2_kernvec kerning[256][256]; /* kerning[left char][right char] */
 } ft2_kerning_t;
 
+typedef struct ft2_glyph_tree_s
+{
+       struct ft2_glyph_tree_s* next[0x10];
+       struct glyph_s *endglyph;
+} ft2_glyph_tree_t;
+
+typedef struct ft2_font_size_s
+{
+       float         size;
+       // the actual size used in the freetype code
+       // by convention, the requested size is the height of the font's bounding box.
+       float         intSize;
+       int           glyphSize;
+
+       // For quick access, the first 256 glyphs
+       // are stored here - but not preloaded!
+       struct glyph_s *main_glyphs[256];
+       ft2_glyph_tree_t glyphtree;
+
+       // contains the kerning information for the first 256 characters
+       // for the other characters, we will lookup the kerning information
+       // ft2_kerning_t kerning;
+       // safes us the trouble of calculating these over and over again
+       double        sfx, sfy;
+       // the width_of for the image-font, pixel-snapped for this size
+       float         width_of[256];
+} ft2_font_size_t;
+
 typedef struct ft2_font_s
 {
        char            name[64];
@@ -47,20 +76,49 @@ typedef struct ft2_font_s
        //fs_offset_t     datasize;
        void           *face;
 
+       ft2_font_size_t     font_sizes[MAX_FONT_SIZES];
+       int             num_size;
+
+/* DEPRECATED:
        // an unordered array of ordered linked lists of glyph maps for a specific size
        ft2_font_map_t *font_maps[MAX_FONT_SIZES];
        int             num_sizes;
+*/
 
        // attachments
        size_t            attachmentcount;
        ft2_attachment_t *attachments;
 
        ft2_settings_t *settings;
-
        // fallback mechanism
        struct ft2_font_s *next;
+
+       // Virtual2Real translated sizes
+       float              req_sizes[MAX_FONT_SIZES];
 } ft2_font_t;
 
+typedef struct glyph_s
+{
+       qboolean image;
+       // we keep the quad coords here only currently
+       // if you need other info, make Font_LoadMapForIndex fill it into this slot
+       float txmin; // texture coordinate in [0,1]
+       float txmax;
+       float tymin;
+       float tymax;
+       float vxmin;
+       float vxmax;
+       float vymin;
+       float vymax;
+       float advance_x;
+       float advance_y;
+
+       ft2_glyphtex_t *glyphtex;
+       // So we don't need to care about what glyphtex looks like outside the font code:
+       rtexture_t     *tex;
+} glyph_t;
+
+
 void            Font_CloseLibrary(void);
 void            Font_Init(void);
 qboolean        Font_OpenLibrary(void);
@@ -70,12 +128,18 @@ void            Font_UnloadFont(ft2_font_t *font);
 // for example, you render at a size of 12.4, and a font of size 12 has been loaded
 // in such a case, *outw and *outh are set to 12, which is often a good alternative size
 int             Font_IndexForSize(ft2_font_t *font, float size, float *outw, float *outh);
-ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index);
 qboolean        Font_LoadFont(const char *name, dp_font_t *dpfnt);
-qboolean        Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy);
-qboolean        Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy);
+// We use sizeindex to make sure we don't try finding the index anew every time...
+qboolean        Font_GetKerning(ft2_font_t *font, int sizeindex, float w, float h, Uchar left, Uchar right, float *outx, float *outy);
+glyph_t*        Font_GetGlyph(ft2_font_t *font, int sizeindex, float w, float h, Uchar ch);
 float           Font_VirtualToRealSize(float sz);
 float           Font_SnapTo(float val, float snapwidth);
+
+
+
+
+//ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index);
+//qboolean        Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy);
 // since this is used on a font_map_t, let's name it FontMap_*
-ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch);
+//ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch);
 #endif // DP_FREETYPE2_H__
index 3f08187db52e355bc65d1058273c3f75e0ac49da..e475a63ab5f1b906b82371b45d8f51f919882100 100644 (file)
@@ -1,6 +1,55 @@
 #ifndef FT2_PRIVATE_H__
 #define FT2_PRIVATE_H__
 
+// FIXME: When all this is done: rename
+// this to glyph_slot_s again...
+
+// How big textures should be...
+#define FONT_GLYPHTEX_WIDTH 512
+#define FONT_GLYPHTEX_HEIGHT 512
+
+typedef struct ft2_glyphtex_s
+{
+       int width, height;
+       int texflags;
+
+       rtexture_t    *tex;
+       //unsigned char *data;
+       int            bytesPerPixel;
+       //int            pitch;
+       /* FIXME: remove this, I have it here so I don't need to switch over to model_shared.h to see the defs :P
+void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height);
+void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state);
+void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state);
+qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy);
+*/
+       mod_alloclightmap_state_t blockstate;
+
+       // This acts as a reference count for glyphs
+       // When a glyph is loaded, this gets increased
+       // When a font is unloaded, this is decreased
+       // for every glyph on this texture. If we hit
+       // 0, we remove the texture completely.
+       // The goal is that if there's only few characters
+       // being used, but many characters allocated, we
+       // destroy this texture to have the used glyphs be
+       // moved to a more-active texture.
+       int glyph_count;
+       //int lastusedframe; // <- useful, we unload unused images
+
+       // NOTE: We also need a way to remove glyphs
+       // from still-existing fonts when we remove
+       // this texture, to force them to reload them.
+       // NOTE: Rather then re-rendering, we could just copy them directly.
+       struct glyph_s *first_glyph;
+       struct glyph_s *last_glyph; // <- for faster insertion
+
+       struct ft2_glyphtex_s *prev;
+       struct ft2_glyphtex_s *next;
+} ft2_glyphtex_t;
+
+ft2_glyphtex_t *Font_New_GlyphTex(int width, int height);
+
 // anything should work, but I recommend multiples of 8
 // since the texture size should be a power of 2
 #define FONT_CHARS_PER_LINE 16
@@ -55,7 +104,7 @@ struct ft2_attachment_s
 };
 
 //qboolean Font_LoadMapForIndex(ft2_font_t *font, Uchar _ch, ft2_font_map_t **outmap);
-qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap);
+//qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap);
 
 void font_start(void);
 void font_shutdown(void);
index dab25100246b0f597060a34a5bce785b99aa4853..6ed29870b258607bebb0faea0557eae1babfe3a7 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -765,11 +765,18 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale,
        {
                for (i = 0; i < MAX_FONT_SIZES; ++i)
                {
+                       /*
                        ft2_font_map_t *map = Font_MapForIndex(fnt->ft2, i);
                        if (!map)
                                break;
                        for(ch = 0; ch < 256; ++ch)
                                map->width_of[ch] = Font_SnapTo(fnt->width_of[ch], 1/map->size);
+                       */
+                       ft2_font_size_t *ftsize = &fnt->ft2->font_sizes[i];
+                       for (ch = 0; ch < 256; ++ch) {
+                               if (ftsize->size > 0)
+                                       ftsize->width_of[ch] = Font_SnapTo(fnt->width_of[ch], 1/ftsize->size);
+                       }
                }
        }
 
@@ -1323,16 +1330,24 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
        int colorindex = STRING_COLOR_DEFAULT;
        size_t i;
        float x = 0;
-       Uchar ch, mapch, nextch;
+       Uchar ch, nextch;
        Uchar prevch = 0; // used for kerning
        int tempcolorindex;
        float kx;
-       int map_index = 0;
        size_t bytes_left;
+       /* DEPRECATED:
+       int map_index = 0;
        ft2_font_map_t *fontmap = NULL;
        ft2_font_map_t *map = NULL;
        //ft2_font_map_t *prevmap = NULL;
+       */
+       int size_index = 0;
        ft2_font_t *ft2 = fnt->ft2;
+       ft2_font_size_t *ft2size = NULL;
+       glyph_t *glyph = NULL;
+       rtexture_t *ft2tex = NULL;
+       qboolean oldstyle_char = false;
+       //qboolean oldstyle_char = false;
        // float ftbase_x;
        qboolean snap = true;
        qboolean least_one = false;
@@ -1353,10 +1368,12 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
        if (ft2 != NULL)
        {
                if (snap)
-                       map_index = Font_IndexForSize(ft2, h, &w, &h);
+                       size_index = Font_IndexForSize(ft2, h, &w, &h);
                else
-                       map_index = Font_IndexForSize(ft2, h, NULL, NULL);
-               fontmap = Font_MapForIndex(ft2, map_index);
+                       size_index = Font_IndexForSize(ft2, h, NULL, NULL);
+               //fontmap = Font_MapForIndex(ft2, map_index);
+               if (size_index >= 0)
+                       ft2size = &ft2->font_sizes[size_index];
        }
 
        dw = w * sw;
@@ -1382,8 +1399,8 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
        //if (snap)
        //      x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway
 
-       if (fontmap)
-               width_of = fontmap->width_of;
+       if (ft2size)
+               width_of = ft2size->width_of;
        else
                width_of = fnt->width_of;
 
@@ -1395,7 +1412,7 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
                i = text - text_start;
                if (!ch)
                        break;
-               if (ch == ' ' && !fontmap)
+               if (ch == ' ' && !ft2size)
                {
                        if(!least_one || i0) // never skip the first character
                        if(x + width_of[(int) ' '] * dw > maxwidth)
@@ -1460,14 +1477,16 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
                }
                ch = nextch;
 
-               if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
+               if (ft2size)
+                       glyph = Font_GetGlyph(ft2, size_index, w, h, ch);
+
+               if (!ft2size || (ch <= 0xFF && glyph->image) || (ch >= 0xE000 && ch <= 0xE0FF))
                {
                        if (ch > 0xE000)
                                ch -= 0xE000;
                        if (ch > 0xFF)
                                continue;
-                       if (fontmap)
-                               map = ft2_oldstyle_map;
+                       oldstyle_char = true;
                        prevch = 0;
                        if(!least_one || i0) // never skip the first character
                        if(x + width_of[ch] * dw > maxwidth)
@@ -1477,6 +1496,7 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
                        }
                        x += width_of[ch] * dw;
                } else {
+                       /*
                        if (!map || map == ft2_oldstyle_map || ch < map->start || ch >= map->start + FONT_CHARS_PER_MAP)
                        {
                                map = FontMap_FindForChar(fontmap, ch);
@@ -1492,7 +1512,15 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
                        if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL))
                                x += kx * dw;
                        x += map->glyphs[mapch].advance_x * dw;
+                       */
+                       if (oldstyle_char || glyph->tex != ft2tex) {
+                               oldstyle_char = false;
+                               ft2tex = glyph->tex;
+                       }
                        //prevmap = map;
+                       if (prevch && Font_GetKerning(ft2, size_index, w, h, prevch, ch, &kx, NULL))
+                               x += kx * dw;
+                       x += glyph->advance_x * dw;
                        prevch = ch;
                }
        }
@@ -1516,17 +1544,25 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
        static float vertex3f[QUADELEMENTS_MAXQUADS*4*3];
        static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2];
        static float color4f[QUADELEMENTS_MAXQUADS*4*4];
-       Uchar ch, mapch, nextch;
+       Uchar ch, nextch;
        Uchar prevch = 0; // used for kerning
        int tempcolorindex;
+       /*
        int map_index = 0;
        //ft2_font_map_t *prevmap = NULL; // the previous map
        ft2_font_map_t *map = NULL;     // the currently used map
        ft2_font_map_t *fontmap = NULL; // the font map for the size
+       */
+       qboolean oldstyle_char = false;
+       int size_index = 0;
        float ftbase_y;
        const char *text_start = text;
        float kx, ky;
        ft2_font_t *ft2 = fnt->ft2;
+       ft2_font_size_t *ft2size = NULL;
+       //ft2_glyphtex_t *ft2tex = NULL; // Used to reduce SetupShader calls and maximize batches
+       rtexture_t *ft2tex = NULL;
+       glyph_t *glyph = NULL;
        qboolean snap = true;
        float pix_x, pix_y;
        size_t bytes_left;
@@ -1550,10 +1586,12 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
        if (ft2 != NULL)
        {
                if (snap)
-                       map_index = Font_IndexForSize(ft2, h, &w, &h);
+                       size_index = Font_IndexForSize(ft2, h, &w, &h);
                else
-                       map_index = Font_IndexForSize(ft2, h, NULL, NULL);
-               fontmap = Font_MapForIndex(ft2, map_index);
+                       size_index = Font_IndexForSize(ft2, h, NULL, NULL);
+               //fontmap = Font_MapForIndex(ft2, map_index);
+               if (size_index >= 0)
+                       ft2size = &ft2->font_sizes[size_index];
        }
 
        dw = w * sw;
@@ -1571,7 +1609,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                return startx + DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, &maxlen, w, h, sw, sh, NULL, ignorecolorcodes, fnt, 1000000000);
 
 //     R_Mesh_ResetTextureState();
-       if (!fontmap)
+       if (!ft2size)
                R_Mesh_TexBind(0, fnt->tex);
        R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
 
@@ -1591,8 +1629,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
        pix_x = vid.width / vid_conwidth.value;
        pix_y = vid.height / vid_conheight.value;
 
-       if (fontmap)
-               width_of = fontmap->width_of;
+       if (ft2size)
+               width_of = ft2size->width_of;
        else
                width_of = fnt->width_of;
 
@@ -1623,7 +1661,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                        i = text - text_start;
                        if (!ch)
                                break;
-                       if (ch == ' ' && !fontmap)
+                       if (ch == ' ' && !ft2size)
                        {
                                x += width_of[(int) ' '] * dw;
                                continue;
@@ -1689,15 +1727,18 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                x += 1.0/pix_x * r_textshadow.value;
                                y += 1.0/pix_y * r_textshadow.value;
                        }
-                       if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF))
+
+                       if (ft2size)
+                               glyph = Font_GetGlyph(ft2, size_index, w, h, ch);
+                       if (!ft2size || (ch <= 0xFF && glyph->image) || (ch >= 0xE000 && ch <= 0xE0FF))
                        {
                                if (ch >= 0xE000)
                                        ch -= 0xE000;
                                if (ch > 0xFF)
                                        goto out;
-                               if (fontmap)
+                               if (ft2size)
                                {
-                                       if (map != ft2_oldstyle_map)
+                                       if (!oldstyle_char)
                                        {
                                                if (batchcount)
                                                {
@@ -1710,7 +1751,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                                        av = vertex3f;
                                                }
                                                R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
-                                               map = ft2_oldstyle_map;
+                                               oldstyle_char = true;
                                        }
                                }
                                prevch = 0;
@@ -1759,6 +1800,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                }
                                x += width_of[ch] * dw;
                        } else {
+                               /* DEPRECATED:
                                if (!map || map == ft2_oldstyle_map || ch < map->start || ch >= map->start + FONT_CHARS_PER_MAP)
                                {
                                        // new charmap - need to render
@@ -1790,13 +1832,34 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                        }
                                        R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
                                }
+                               */
+
+                               // DEPRECATED: mapch = ch - map->start;
+                               // DEPRECATED: thisw = map->glyphs[mapch].advance_x;
 
-                               mapch = ch - map->start;
-                               thisw = map->glyphs[mapch].advance_x;
+                               // this is done above to get the actual glyph's .image value
+                               // glyph = Font_GetGlyph(ft2, size_index, w, h, ch);
+                               thisw = glyph->advance_x;
+
+                               if (oldstyle_char || glyph->tex != ft2tex) {
+                                       oldstyle_char = false;
+                                       ft2tex = glyph->tex;
+                                       if (batchcount)
+                                       {
+                                               R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
+                                               R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
+                                               batchcount = 0;
+                                               ac = color4f;
+                                               at = texcoord2f;
+                                               av = vertex3f;
+                                       }
+                                       R_SetupShader_Generic(glyph->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
+                               }
 
                                //x += ftbase_x;
                                y += ftbase_y;
-                               if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
+                               //if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky))
+                               if (prevch && Font_GetKerning(ft2, size_index, w, h, prevch, ch, &kx, &ky))
                                {
                                        x += kx * dw;
                                        y += ky * dh;
@@ -1807,14 +1870,14 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                ac[ 4] = DrawQ_Color[0]; ac[ 5] = DrawQ_Color[1]; ac[ 6] = DrawQ_Color[2]; ac[ 7] = DrawQ_Color[3];
                                ac[ 8] = DrawQ_Color[0]; ac[ 9] = DrawQ_Color[1]; ac[10] = DrawQ_Color[2]; ac[11] = DrawQ_Color[3];
                                ac[12] = DrawQ_Color[0]; ac[13] = DrawQ_Color[1]; ac[14] = DrawQ_Color[2]; ac[15] = DrawQ_Color[3];
-                               at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin;
-                               at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin;
-                               at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax;
-                               at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax;
-                               av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10;
-                               av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10;
-                               av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10;
-                               av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10;
+                               at[0] = glyph->txmin; at[1] = glyph->tymin;
+                               at[2] = glyph->txmax; at[3] = glyph->tymin;
+                               at[4] = glyph->txmax; at[5] = glyph->tymax;
+                               at[6] = glyph->txmin; at[7] = glyph->tymax;
+                               av[ 0] = x + dw * glyph->vxmin; av[ 1] = y + dh * glyph->vymin; av[ 2] = 10;
+                               av[ 3] = x + dw * glyph->vxmax; av[ 4] = y + dh * glyph->vymin; av[ 5] = 10;
+                               av[ 6] = x + dw * glyph->vxmax; av[ 7] = y + dh * glyph->vymax; av[ 8] = 10;
+                               av[ 9] = x + dw * glyph->vxmin; av[10] = y + dh * glyph->vymax; av[11] = 10;
                                //x -= ftbase_x;
                                y -= ftbase_y;
 
index 57c257f27d85d1ecfff4e5909a8e8a426d8c4ef9..7afac05d9acae41efc5e0a0d8d278a04e422b92b 100644 (file)
@@ -2015,6 +2015,36 @@ rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *
        return (rtexture_t *)glt;
 }
 
+void R_SaveTextureTGAFile(rtexture_t *rt, const char *filename, qboolean hasalpha)
+{
+#ifdef USE_GLES2
+       return -1;
+#else
+       GLint internalformat;
+       GLint oldbindtexnum;
+       unsigned char *data;
+       gltexture_t *glt = (gltexture_t *)rt;
+
+       GL_ActiveTexture(0);
+       oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
+       qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
+       qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
+       if (hasalpha)
+       {
+               data = Mem_Alloc(tempmempool, glt->tilewidth * glt->tileheight * 4);
+               qglGetTexImage(gltexturetypeenums[glt->texturetype], 0, GL_BGRA, GL_UNSIGNED_BYTE, data); CHECKGLERROR
+               Image_WriteTGABGRA(filename, glt->tilewidth, glt->tileheight, data);
+               Mem_Free(data);
+       } else {
+               data = Mem_Alloc(tempmempool, glt->tilewidth * glt->tileheight * 3);
+               qglGetTexImage(gltexturetypeenums[glt->texturetype], 0, GL_BGR, GL_UNSIGNED_BYTE, data); CHECKGLERROR
+               Image_WriteTGABGR_preflipped(filename, glt->tilewidth, glt->tileheight, data);
+               Mem_Free(data);
+       }
+       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+#endif
+}
+
 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
 {
 #ifdef USE_GLES2
index 7a15c8acb0ec29d6f823e1e579f2b3ce2a182d58..cafbd184741f432372ddfc21958e268d94441687 100644 (file)
@@ -2632,7 +2632,7 @@ static void Mod_Q1BSP_LoadFaces(sizebuf_t *sb)
                int stainmapsize = 0;
                mod_alloclightmap_state_t allocState;
 
-               Mod_AllocLightmap_Init(&allocState, lightmapsize, lightmapsize);
+               Mod_AllocLightmap_Init(&allocState, lightmapsize, lightmapsize, loadmodel->mempool);
                for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++)
                {
                        int i, iu, iv, lightmapx = 0, lightmapy = 0;
index 5d06edc5b869c07527550d466025646f4b7b02be..74e041221a19b0d082325dc10a4d584b2445d3f5 100644 (file)
@@ -3462,14 +3462,14 @@ static void Mod_Decompile_f(void)
        }
 }
 
-void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height)
+void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height, mempool_t *mempool)
 {
        int y;
        memset(state, 0, sizeof(*state));
        state->width = width;
        state->height = height;
        state->currentY = 0;
-       state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(loadmodel->mempool, state->height * sizeof(*state->rows));
+       state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
        for (y = 0;y < state->height;y++)
        {
                state->rows[y].currentX = 0;
@@ -4181,7 +4181,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
        lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
        //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
-       Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
+       Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize, model->mempool);
        lightmapnumber = 0;
        for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
        {
@@ -4229,7 +4229,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
                                surfaceindex = -1;
                                lightmapnumber = 0;
                                Mod_AllocLightmap_Free(&lmstate);
-                               Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
+                               Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize, model->mempool);
                                break;
                        }
                        // if we have maxed out the lightmap size, and this triangle does
index f4e2e3c5aef4e6926d3ca9c5be649575f32dd587..85865b6e875a4aac780b2427993283d86d637c1c 100644 (file)
@@ -1153,7 +1153,7 @@ typedef struct mod_alloclightmap_state_s
 }
 mod_alloclightmap_state_t;
 
-void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height);
+void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height, mempool_t *mempool);
 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state);
 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state);
 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy);