]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - ft2.c
attempt to fix white flicker when r_water is toggled
[xonotic/darkplaces.git] / ft2.c
diff --git a/ft2.c b/ft2.c
index 1fd78bd31349e47387c8129e310855e6eaea62d1..d1974f56fb871df61332a67221518eb51f40fd6e 100644 (file)
--- a/ft2.c
+++ b/ft2.c
@@ -35,6 +35,10 @@ CVars introduced with the freetype extension
 cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"};
 cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
 cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
+cvar_t r_font_hinting = {CVAR_SAVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"};
+cvar_t r_font_antialias = {CVAR_SAVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */};
+cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
+cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
 
 /*
 ================================================================================
@@ -169,11 +173,11 @@ qboolean Font_OpenLibrary (void)
 {
        const char* dllnames [] =
        {
-#if defined(WIN64)
-               #error path for freetype 2 dll
-#elif defined(WIN32)
-               #error path for freetype 2 dll
+#if defined(WIN32)
+               "freetype6.dll",
+               "libfreetype-6.dll",
 #elif defined(MACOSX)
+               "libfreetype.6.dylib",
                "libfreetype.dylib",
 #else
                "libfreetype.so.6",
@@ -255,6 +259,12 @@ void Font_Init(void)
        Cvar_RegisterVariable(&r_font_disable_freetype);
        Cvar_RegisterVariable(&r_font_use_alpha_textures);
        Cvar_RegisterVariable(&r_font_size_snapping);
+       Cvar_RegisterVariable(&r_font_hinting);
+       Cvar_RegisterVariable(&r_font_antialias);
+       Cvar_RegisterVariable(&r_font_kerning);
+       Cvar_RegisterVariable(&developer_font);
+       // let's open it at startup already
+       Font_OpenLibrary();
 }
 
 /*
@@ -290,8 +300,29 @@ qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
        return true;
 }
 
+float Font_VirtualToRealSize(float sz)
+{
+       int vh, vw, si;
+       float sn;
+       if(sz < 0)
+               return sz;
+       vw = ((vid.width > 0) ? vid.width : vid_width.value);
+       vh = ((vid.height > 0) ? vid.height : vid_height.value);
+       // now try to scale to our actual size:
+       sn = sz * vh / vid_conheight.value;
+       si = (int)sn;
+       if ( sn - (float)si >= 0.5 )
+               ++si;
+       return si;
+}
+
+float Font_SnapTo(float val, float snapwidth)
+{
+       return floor(val / snapwidth + 0.5f) * snapwidth;
+}
+
 static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font);
-static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning);
+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;
@@ -347,9 +378,9 @@ qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
                        break;
                }
                count = 0;
-               for (s = 0; s < MAX_FONT_SIZES; ++s)
+               for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
                {
-                       if (Font_LoadSize(fb, dpfnt->req_sizes[s], true, false))
+                       if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true))
                                ++count;
                }
                if (!count)
@@ -374,9 +405,9 @@ qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
        }
 
        count = 0;
-       for (s = 0; s < MAX_FONT_SIZES; ++s)
+       for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s)
        {
-               if (Font_LoadSize(ft2, dpfnt->req_sizes[s], false, false))
+               if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false))
                        ++count;
        }
        if (!count)
@@ -483,13 +514,14 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font)
        return true;
 }
 
+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_LoadSize(ft2_font_t *font, float size, qboolean no_texture, qboolean no_kerning)
+static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
 {
        int map_index;
        ft2_font_map_t *fmap, temp;
 
-       if (IS_NAN(size))
+       if (!(size > 0.001f && size < 1000.0f))
                size = 0;
 
        if (!size)
@@ -497,69 +529,72 @@ static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean no_texture,
        if (size < 2) // bogus sizes are not allowed - and they screw up our allocations
                return false;
 
-       if (!no_texture)
+       for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
        {
-               for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index)
-               {
-                       if (!font->font_maps[map_index])
-                               break;
-                       // if a similar size has already been loaded, ignore this one
-                       //abs(font->font_maps[map_index]->size - size) < 4
-                       if (font->font_maps[map_index]->size == size)
-                               return true;
-               }
+               if (!font->font_maps[map_index])
+                       break;
+               // if a similar size has already been loaded, ignore this one
+               //abs(font->font_maps[map_index]->size - size) < 4
+               if (font->font_maps[map_index]->size == size)
+                       return true;
+       }
 
-               if (map_index >= MAX_FONT_SIZES)
-                       return false;
+       if (map_index >= MAX_FONT_SIZES)
+               return false;
 
-               memset(&temp, 0, sizeof(temp));
-               temp.size = size;
-               temp.glyphSize = CeilPowerOf2(size*2);
-               temp.sfx = (1.0/64.0)/(double)size;
-               temp.sfy = (1.0/64.0)/(double)size;
-               temp.intSize = -1; // negative value: LoadMap must search now :)
-               if (!Font_LoadMap(font, &temp, 0, &fmap))
-               {
-                       Con_Printf("ERROR: can't load the first character map for %s\n"
-                                  "This is fatal\n",
-                                  font->name);
-                       Font_UnloadFont(font);
-                       return false;
-               }
-               font->font_maps[map_index] = temp.next;
+       if (check_only) {
+               FT_Face fontface;
+               if (font->image_font)
+                       fontface = (FT_Face)font->next->face;
+               else
+                       fontface = (FT_Face)font->face;
+               return (Font_SearchSize(font, fontface, size) > 0);
+       }
 
-               fmap->sfx = temp.sfx;
-               fmap->sfy = temp.sfy;
+       memset(&temp, 0, sizeof(temp));
+       temp.size = size;
+       temp.glyphSize = CeilPowerOf2(size*2);
+       temp.sfx = (1.0/64.0)/(double)size;
+       temp.sfy = (1.0/64.0)/(double)size;
+       temp.intSize = -1; // negative value: LoadMap must search now :)
+       if (!Font_LoadMap(font, &temp, 0, &fmap))
+       {
+               Con_Printf("ERROR: can't load the first character map for %s\n"
+                          "This is fatal\n",
+                          font->name);
+               Font_UnloadFont(font);
+               return false;
        }
-       if (!no_kerning)
+       font->font_maps[map_index] = temp.next;
+
+       fmap->sfx = temp.sfx;
+       fmap->sfy = temp.sfy;
+
+       // load the default kerning vector:
+       if (font->has_kerning)
        {
-               // load the default kerning vector:
-               if (font->has_kerning)
+               Uchar l, r;
+               FT_Vector kernvec;
+               for (l = 0; l < 256; ++l)
                {
-                       Uchar l, r;
-                       FT_Vector kernvec;
-                       for (l = 0; l < 256; ++l)
+                       for (r = 0; r < 256; ++r)
                        {
-                               for (r = 0; r < 256; ++r)
+                               FT_ULong ul, ur;
+                               ul = qFT_Get_Char_Index(font->face, l);
+                               ur = qFT_Get_Char_Index(font->face, r);
+                               if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
                                {
-                                       FT_ULong ul, ur;
-                                       ul = qFT_Get_Char_Index(font->face, l);
-                                       ur = qFT_Get_Char_Index(font->face, r);
-                                       if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
-                                       {
-                                               fmap->kerning.kerning[l][r][0] = 0;
-                                               fmap->kerning.kerning[l][r][1] = 0;
-                                       }
-                                       else
-                                       {
-                                               fmap->kerning.kerning[l][r][0] = (kernvec.x >> 6) / fmap->size;
-                                               fmap->kerning.kerning[l][r][1] = (kernvec.y >> 6) / fmap->size;
-                                       }
+                                       fmap->kerning.kerning[l][r][0] = 0;
+                                       fmap->kerning.kerning[l][r][1] = 0;
+                               }
+                               else
+                               {
+                                       fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size);
+                                       fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size);
                                }
                        }
                }
        }
-
        return true;
 }
 
@@ -570,20 +605,26 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
        int nval;
        int matchsize = -10000;
        int m;
-       int size;
-       float fsize;
+       float fsize_x, fsize_y;
        ft2_font_map_t **maps = font->font_maps;
 
-       fsize = _fsize * vid.height / vid_conheight.value;
+       fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
+       if(outw && *outw)
+               fsize_x = *outw * vid.width / vid_conwidth.value;
+       if(outh && *outh)
+               fsize_y = *outh * vid.height / vid_conheight.value;
 
-       if (fsize < 0)
-               size = 16;
+       if (fsize_x < 0)
+       {
+               if(fsize_y < 0)
+                       fsize_x = fsize_y = 16;
+               else
+                       fsize_x = fsize_y;
+       }
        else
        {
-               // round up
-               size = (int)fsize;
-               if (fsize - (float)size >= 0.49)
-                       ++size;
+               if(fsize_y < 0)
+                       fsize_y = fsize_x;
        }
 
        for (m = 0; m < MAX_FONT_SIZES; ++m)
@@ -591,7 +632,7 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
                if (!maps[m])
                        continue;
                // "round up" to the bigger size if two equally-valued matches exist
-               nval = abs(maps[m]->size - size);
+               nval = 0.5 * (abs(maps[m]->size - fsize_x) + abs(maps[m]->size - fsize_y));
                if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size))
                {
                        value = nval;
@@ -603,14 +644,9 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
        }
        if (value <= r_font_size_snapping.value)
        {
-               if (outw && outh)
-               {
-                       if (!*outh) *outh = *outw;
-                       if (!*outw) *outw = *outh;
-               }
-               // keep the aspect
+               // 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 * *outw / _fsize;
+               if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
        }
        return match;
 }
@@ -651,7 +687,7 @@ static qboolean Font_SetSize(ft2_font_t *font, float w, float h)
 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;
-       if (!font->has_kerning)
+       if (!font->has_kerning || !r_font_kerning.integer)
                return false;
        if (map_index < 0 || map_index >= MAX_FONT_SIZES)
                return false;
@@ -660,9 +696,10 @@ qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h
                return false;
        if (left < 256 && right < 256)
        {
+               //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w));
                // quick-kerning, be aware of the size: scale it
-               if (outx) *outx = fmap->kerning.kerning[left][right][0] * w / (float)fmap->size;
-               if (outy) *outy = fmap->kerning.kerning[left][right][1] * h / (float)fmap->size;
+               if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size);
+               if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size);
                return true;
        }
        else
@@ -671,6 +708,7 @@ qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h
                FT_ULong ul, ur;
 
                //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size))
+#if 0
                if (!Font_SetSize(font, w, h))
                {
                        // this deserves an error message
@@ -681,8 +719,23 @@ qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h
                ur = qFT_Get_Char_Index(font->face, right);
                if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
                {
-                       if (outx) *outx = kernvec.x * fmap->sfx;
-                       if (outy) *outy = kernvec.y * fmap->sfy;
+                       if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);
+                       if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);
+                       return true;
+               }
+#endif
+               if (!Font_SetSize(font, fmap->intSize, fmap->intSize))
+               {
+                       // this deserves an error message
+                       Con_Printf("Failed to get kerning for %s\n", font->name);
+                       return false;
+               }
+               ul = qFT_Get_Char_Index(font->face, left);
+               ur = qFT_Get_Char_Index(font->face, right);
+               if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec))
+               {
+                       if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size);
+                       if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size);
                        return true;
                }
                return false;
@@ -733,6 +786,27 @@ void Font_UnloadFont(ft2_font_t *font)
        }
 }
 
+static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size)
+{
+       float intSize = size;
+       while (1)
+       {
+               if (!Font_SetSize(font, intSize, intSize))
+               {
+                       Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize);
+                       return -1;
+               }
+               if ((fontface->size->metrics.height>>6) <= size)
+                       return intSize;
+               if (intSize < 2)
+               {
+                       Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size);
+                       return -1;
+               }
+               --intSize;
+       }
+}
+
 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];
@@ -741,6 +815,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
        FT_ULong ch, mapch;
        int status;
        int tp;
+       FT_Int32 load_flags;
 
        int pitch;
        int gR, gC; // glyph position: row and column
@@ -763,12 +838,52 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
        else
                fontface = (FT_Face)font->face;
 
+       switch(r_font_antialias.integer)
+       {
+               case 0:
+                       switch(r_font_hinting.integer)
+                       {
+                               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(r_font_hinting.integer)
+                       {
+                               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;
+       }
+
        //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size);
        //if (status)
        if (font->image_font && mapstart->intSize < 0)
                mapstart->intSize = mapstart->size;
        if (mapstart->intSize < 0)
        {
+               /*
                mapstart->intSize = mapstart->size;
                while (1)
                {
@@ -786,8 +901,10 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                        }
                        --mapstart->intSize;
                }
-               if (developer.integer)
-                       Con_Printf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
+               */
+               if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0)
+                       return false;
+               Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size);
        }
 
        if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize))
@@ -818,6 +935,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                Mem_Free(map);
                return false;
        }
+       memset(map->width_of, 0, sizeof(map->width_of));
 
        // initialize as white texture with zero alpha
        tp = 0;
@@ -856,8 +974,8 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
 
                mapch = ch - map->start;
 
-               if (developer.integer)
-                       Con_Print("glyphinfo: ------------- GLYPH INFO -----------------\n");
+               if (developer_font.integer)
+                       Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n");
 
                ++gC;
                if (gC >= FONT_CHARS_PER_LINE)
@@ -890,7 +1008,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                                glyphIndex = qFT_Get_Char_Index(face, ch);
                                if (glyphIndex == 0)
                                        continue;
-                               status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
+                               status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
                                if (status)
                                        continue;
                                break;
@@ -908,11 +1026,11 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                {
                        usefont = font;
                        face = font->face;
-                       status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER);
+                       status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags);
                        if (status)
                        {
                                //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name);
-                               Con_Printf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
+                               Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name);
                                continue;
                        }
                }
@@ -934,24 +1052,24 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                switch (bmp->pixel_mode)
                {
                case FT_PIXEL_MODE_MONO:
-                       if (developer.integer)
-                               Con_Print("glyphinfo:   Pixel Mode: MONO\n");
+                       if (developer_font.integer)
+                               Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
                        break;
                case FT_PIXEL_MODE_GRAY2:
-                       if (developer.integer)
-                               Con_Print("glyphinfo:   Pixel Mode: GRAY2\n");
+                       if (developer_font.integer)
+                               Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
                        break;
                case FT_PIXEL_MODE_GRAY4:
-                       if (developer.integer)
-                               Con_Print("glyphinfo:   Pixel Mode: GRAY4\n");
+                       if (developer_font.integer)
+                               Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
                        break;
                case FT_PIXEL_MODE_GRAY:
-                       if (developer.integer)
-                               Con_Print("glyphinfo:   Pixel Mode: GRAY\n");
+                       if (developer_font.integer)
+                               Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
                        break;
                default:
-                       if (developer.integer)
-                               Con_Printf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
+                       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, mapstart->size, bmp->pixel_mode);
                        return false;
@@ -968,14 +1086,14 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                                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;
+                                       *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:
@@ -994,8 +1112,8 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                                for (x = 0; x < bmp->width; x += 2)
                                {
                                        unsigned char ch = *src++;
-                                       *dst = ( ((ch & 0xF0) >> 4) * 0x24); dst += bytesPerPixel;
-                                       *dst = ( ((ch & 0x0F) ) * 0x24); dst += bytesPerPixel;
+                                       *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
+                                       *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
                                }
                                break;
                        case FT_PIXEL_MODE_GRAY:
@@ -1018,37 +1136,43 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                        // old way
                        // double advance = (double)glyph->metrics.horiAdvance * map->sfx;
 
-                       double bearingX = (glyph->metrics.horiBearingX >> 6) / map->size;
-                       double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
-                       double advance = (glyph->advance.x >> 6) / map->size;
-                       double mWidth = (glyph->metrics.width >> 6) / map->size;
-                       double mHeight = (glyph->metrics.height >> 6) / map->size;
+                       double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size;
+                       //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size;
+                       double advance = (glyph->advance.x / 64.0) / map->size;
+                       //double mWidth = (glyph->metrics.width >> 6) / map->size;
+                       //double mHeight = (glyph->metrics.height >> 6) / map->size;
 
-                       mapglyph->vxmin = bearingX;
-                       mapglyph->vxmax = bearingX + mWidth;
-                       mapglyph->vymin = -bearingY;
-                       mapglyph->vymax = mHeight - bearingY;
                        mapglyph->txmin = ( (double)(gC * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
                        mapglyph->txmax = mapglyph->txmin + (double)bmp->width / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) );
                        mapglyph->tymin = ( (double)(gR * map->glyphSize) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
                        mapglyph->tymax = mapglyph->tymin + (double)bmp->rows / ( (double)(map->glyphSize * FONT_CHAR_LINES) );
+                       //mapglyph->vxmin = bearingX;
+                       //mapglyph->vxmax = bearingX + mWidth;
+                       mapglyph->vxmin = glyph->bitmap_left / map->size;
+                       mapglyph->vxmax = mapglyph->vxmin + bmp->width / map->size; // don't ask
+                       //mapglyph->vymin = -bearingY;
+                       //mapglyph->vymax = mHeight - bearingY;
+                       mapglyph->vymin = -glyph->bitmap_top / map->size;
+                       mapglyph->vymax = mapglyph->vymin + bmp->rows / map->size;
+                       //Con_Printf("dpi = %f %f (%f %d) %d %d\n", bmp->width / (mapglyph->vxmax - mapglyph->vxmin), bmp->rows / (mapglyph->vymax - mapglyph->vymin), map->size, map->glyphSize, (int)fontface->size->metrics.x_ppem, (int)fontface->size->metrics.y_ppem);
                        //mapglyph->advance_x = advance * usefont->size;
-                       mapglyph->advance_x = advance;
+                       //mapglyph->advance_x = advance;
+                       mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size);
                        mapglyph->advance_y = 0;
 
-                       if (developer.integer)
+                       if (developer_font.integer)
                        {
-                               Con_Printf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
-                               Con_Printf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
+                               Con_DPrintf("glyphinfo:   Glyph: %lu   at (%i, %i)\n", (unsigned long)ch, gC, gR);
+                               Con_DPrintf("glyphinfo:   %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX);
                                if (ch >= 32 && ch <= 128)
-                                       Con_Printf("glyphinfo:   Character: %c\n", (int)ch);
-                               Con_Printf("glyphinfo:   Vertex info:\n");
-                               Con_Printf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
-                               Con_Printf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
-                               Con_Printf("glyphinfo:   Texture info:\n");
-                               Con_Printf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
-                               Con_Printf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
-                               Con_Printf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
+                                       Con_DPrintf("glyphinfo:   Character: %c\n", (int)ch);
+                               Con_DPrintf("glyphinfo:   Vertex info:\n");
+                               Con_DPrintf("glyphinfo:     X: ( %f  --  %f )\n", mapglyph->vxmin, mapglyph->vxmax);
+                               Con_DPrintf("glyphinfo:     Y: ( %f  --  %f )\n", mapglyph->vymin, mapglyph->vymax);
+                               Con_DPrintf("glyphinfo:   Texture info:\n");
+                               Con_DPrintf("glyphinfo:     S: ( %f  --  %f )\n", mapglyph->txmin, mapglyph->txmax);
+                               Con_DPrintf("glyphinfo:     T: ( %f  --  %f )\n", mapglyph->tymin, mapglyph->tymax);
+                               Con_DPrintf("glyphinfo:   Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y);
                        }
                }
                map->glyphs[mapch].image = false;
@@ -1056,8 +1180,9 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
 
        // create a texture from the data now
 
-       if (developer.integer)
+       if (developer_font.integer > 100)
        {
+               // LordHavoc: why are we writing this?  And why not write it as TGA using the appropriate function?
                // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
                dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
                FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
@@ -1106,7 +1231,7 @@ qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_fo
 
 ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch)
 {
-       while (start && start->start + FONT_CHARS_PER_MAP < ch)
+       while (start && start->start + FONT_CHARS_PER_MAP <= ch)
                start = start->next;
        if (start && start->start > ch)
                return NULL;