X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=ft2.c;h=1e1853d0b4fdc4b43ffcdd2ba1614f634e6060fe;hb=c6f88b6f94206e34ed2e322c0f2aa9831714b017;hp=1e31dc4fa07054b5a45414d399253b9ad34cbd2c;hpb=f6dad115011a31cebb74ff8f55a9ea118d5a32eb;p=xonotic%2Fdarkplaces.git diff --git a/ft2.c b/ft2.c index 1e31dc4f..1e1853d0 100644 --- a/ft2.c +++ b/ft2.c @@ -175,7 +175,9 @@ qboolean Font_OpenLibrary (void) { #if defined(WIN32) "freetype6.dll", + "libfreetype-6.dll", #elif defined(MACOSX) + "libfreetype.6.dylib", "libfreetype.dylib", #else "libfreetype.so.6", @@ -261,6 +263,8 @@ void Font_Init(void) Cvar_RegisterVariable(&r_font_antialias); Cvar_RegisterVariable(&r_font_kerning); Cvar_RegisterVariable(&developer_font); + // let's open it at startup already + Font_OpenLibrary(); } /* @@ -296,7 +300,7 @@ qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment) return true; } -static float Font_VirtualToRealSize(float sz) +float Font_VirtualToRealSize(float sz) { int vh, vw, si; float sn; @@ -312,13 +316,13 @@ static float Font_VirtualToRealSize(float sz) return si; } -static float Font_SnapTo(float val, float snapwidth) +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; @@ -374,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, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true, false)) + if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true)) ++count; } if (!count) @@ -401,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, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false, false)) + if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false)) ++count; } if (!count) @@ -510,11 +514,27 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_font_t *font) return true; } +void Font_Postprocess(unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b) +{ + if(imagedata) + { + // perform operation, not exceeding the passed padding values, + // but possibly reducing them + } + else + { + // calculate parameters + *pad_l = *pad_r = *pad_t = *pad_b = 0; + } +} + +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; + int gpad_l, gpad_r, gpad_t, gpad_b; if (!(size > 0.001f && size < 1000.0f)) size = 0; @@ -524,69 +544,74 @@ 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); + } + + Font_Postprocess(NULL, 0, 0, 0, 0, &gpad_l, &gpad_r, &gpad_t, &gpad_b); - fmap->sfx = temp.sfx; - fmap->sfy = temp.sfy; + memset(&temp, 0, sizeof(temp)); + temp.size = size; + temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b)); + 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] = 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); - } + 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; } @@ -778,6 +803,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]; @@ -787,6 +833,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ int status; int tp; FT_Int32 load_flags; + int gpad_l, gpad_r, gpad_t, gpad_b; int pitch; int gR, gC; // glyph position: row and column @@ -854,6 +901,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ mapstart->intSize = mapstart->size; if (mapstart->intSize < 0) { + /* mapstart->intSize = mapstart->size; while (1) { @@ -871,6 +919,9 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ } --mapstart->intSize; } + */ + 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); } @@ -887,6 +938,8 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ return false; } + Font_Postprocess(NULL, 0, 0, 0, 0, &gpad_l, &gpad_r, &gpad_t, &gpad_b); + // copy over the information map->size = mapstart->size; map->intSize = mapstart->intSize; @@ -938,6 +991,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ unsigned char *imagedata, *dst, *src; glyph_slot_t *mapglyph; FT_Face face; + int pad_l, pad_r, pad_t, pad_b; mapch = ch - map->start; @@ -952,6 +1006,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ } imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel; + imagedata += gpad_t * pitch + gpad_l; //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER); // we need the glyphIndex face = font->face; @@ -1008,10 +1063,10 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ w = bmp->width; h = bmp->rows; - if (w > map->glyphSize || h > map->glyphSize) { + if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) { Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h); if (w > map->glyphSize) - w = map->glyphSize; + w = map->glyphSize - gpad_l - gpad_r; if (h > map->glyphSize) h = map->glyphSize; } @@ -1096,6 +1151,12 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ } } + pad_l = gpad_l; + pad_r = gpad_r; + pad_t = gpad_t; + pad_b = gpad_b; + Font_Postprocess(imagedata, pitch, w, h, bytesPerPixel, &pad_l, &pad_r, &pad_t, &pad_b); + // now fill map->glyphs[ch - map->start] mapglyph = &map->glyphs[mapch]; @@ -1110,17 +1171,17 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ //double mHeight = (glyph->metrics.height >> 6) / map->size; 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->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (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->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (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->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / 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; + mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / 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; @@ -1198,7 +1259,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;