src/fontcache.cpp
changeset 5584 1111b4d36e35
parent 5475 2e6990a8c7c4
child 5587 167d9a91ef02
equal deleted inserted replaced
5583:136d8764c7e6 5584:1111b4d36e35
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "functions.h"
       
     6 #include "macros.h"
       
     7 #include "debug.h"
       
     8 #include "table/sprites.h"
       
     9 #include "table/control_codes.h"
       
    10 #include "spritecache.h"
       
    11 #include "gfx.h"
       
    12 #include "string.h"
       
    13 #include "fontcache.h"
       
    14 
       
    15 #ifdef WITH_FREETYPE
       
    16 
       
    17 #include <ft2build.h>
       
    18 #include FT_FREETYPE_H
       
    19 #include FT_GLYPH_H
       
    20 
       
    21 #ifdef WITH_FONTCONFIG
       
    22 #include <fontconfig/fontconfig.h>
       
    23 #endif
       
    24 
       
    25 static FT_Library _library = NULL;
       
    26 static FT_Face _face_small = NULL;
       
    27 static FT_Face _face_medium = NULL;
       
    28 static FT_Face _face_large = NULL;
       
    29 
       
    30 FreeTypeSettings _freetype;
       
    31 
       
    32 enum {
       
    33 	FACE_COLOUR = 1,
       
    34 	SHADOW_COLOUR = 2,
       
    35 };
       
    36 
       
    37 /** Get the font loaded into a Freetype face by using a font-name.
       
    38  * If no appropiate font is found, the function returns an error */
       
    39 #ifdef WIN32
       
    40 #include <windows.h>
       
    41 #include <tchar.h>
       
    42 #include <shlobj.h> // SHGetFolderPath
       
    43 #include "win32.h"
       
    44 
       
    45 /* Get the font file to be loaded into Freetype by looping the registry
       
    46  * location where windows lists all installed fonts. Not very nice, will
       
    47  * surely break if the registry path changes, but it works. Much better
       
    48  * solution would be to use CreateFont, and extract the font data from it
       
    49  * by GetFontData. The problem with this is that the font file needs to be
       
    50  * kept in memory then until the font is no longer needed. This could mean
       
    51  * an additional memory usage of 30MB (just for fonts!) when using an eastern
       
    52  * font for all font sizes */
       
    53 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
       
    54 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
       
    55 static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
       
    56 {
       
    57 	FT_Error err = FT_Err_Cannot_Open_Resource;
       
    58 	HKEY hKey;
       
    59 	LONG ret;
       
    60 	TCHAR vbuffer[MAX_PATH], dbuffer[256];
       
    61 	TCHAR *font_namep;
       
    62 	char *font_path;
       
    63 	uint index;
       
    64 
       
    65 	/* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
       
    66 	 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
       
    67 	 * to retrieve the windows version, we'll just query both */
       
    68 	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
       
    69 	if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
       
    70 
       
    71 	if (ret != ERROR_SUCCESS) {
       
    72 		DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
       
    73 		return err;
       
    74 	}
       
    75 
       
    76 	/* For Unicode we need some conversion between widechar and
       
    77 	 * normal char to match the data returned by RegEnumValue,
       
    78 	 * otherwise just use parameter */
       
    79 #if defined(UNICODE)
       
    80 	font_namep = malloc(MAX_PATH * sizeof(TCHAR));
       
    81 	MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
       
    82 #else
       
    83 	font_namep = (char*)font_name; // only cast because in unicode pointer is not const
       
    84 #endif
       
    85 
       
    86 	for (index = 0;; index++) {
       
    87 		TCHAR *s;
       
    88 		DWORD vbuflen = lengthof(vbuffer);
       
    89 		DWORD dbuflen = lengthof(dbuffer);
       
    90 
       
    91 		ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
       
    92 		if (ret != ERROR_SUCCESS) goto registry_no_font_found;
       
    93 
       
    94 		/* The font names in the registry are of the following 3 forms:
       
    95 		 * - ADMUI3.fon
       
    96 		 * - Book Antiqua Bold (TrueType)
       
    97 		 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
       
    98 		 * We will strip the font-type '()' if any and work with the font name
       
    99 		 * itself, which must match exactly; if...
       
   100 		 * TTC files, font files which contain more than one font are seperated
       
   101 		 * byt '&'. Our best bet will be to do substr match for the fontname
       
   102 		 * and then let FreeType figure out which index to load */
       
   103 		s = _tcschr(vbuffer, _T('('));
       
   104 		if (s != NULL) s[-1] = '\0';
       
   105 
       
   106 		if (_tcschr(vbuffer, _T('&')) == NULL) {
       
   107 			if (_tcsicmp(vbuffer, font_namep) == 0) break;
       
   108 		} else {
       
   109 			if (_tcsstr(vbuffer, font_namep) != NULL) break;
       
   110 		}
       
   111 	}
       
   112 
       
   113 	if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
       
   114 		DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
       
   115 		goto folder_error;
       
   116 	}
       
   117 
       
   118 	/* Some fonts are contained in .ttc files, TrueType Collection fonts. These
       
   119 	 * contain multiple fonts inside this single file. GetFontData however
       
   120 	 * returns the whole file, so we need to check each font inside to get the
       
   121 	 * proper font.
       
   122 	 * Also note that FreeType does not support UNICODE filesnames! */
       
   123 #if defined(UNICODE)
       
   124 	/* We need a cast here back from wide because FreeType doesn't support
       
   125 	 * widechar filenames. Just use the buffer we allocated before for the
       
   126 	 * font_name search */
       
   127 	font_path = (char*)font_namep;
       
   128 	WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
       
   129 #else
       
   130 	font_path = vbuffer;
       
   131 #endif
       
   132 
       
   133 	ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
       
   134 	ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
       
   135 	index = 0;
       
   136 	do {
       
   137 		err = FT_New_Face(_library, font_path, index, face);
       
   138 		if (err != FT_Err_Ok) break;
       
   139 
       
   140 		if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
       
   141 		err = FT_Err_Cannot_Open_Resource;
       
   142 
       
   143 	} while ((FT_Long)++index != (*face)->num_faces);
       
   144 
       
   145 
       
   146 folder_error:
       
   147 #if defined(UNICODE)
       
   148 	free(font_path);
       
   149 #endif
       
   150 registry_no_font_found:
       
   151 	RegCloseKey(hKey);
       
   152 	return err;
       
   153 }
       
   154 #else
       
   155 # ifdef WITH_FONTCONFIG
       
   156 static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
       
   157 {
       
   158 	FT_Error err = FT_Err_Cannot_Open_Resource;
       
   159 
       
   160 	if (!FcInit()) {
       
   161 		ShowInfoF("Unable to load font configuration");
       
   162 	} else {
       
   163 		FcPattern *match;
       
   164 		FcPattern *pat;
       
   165 		FcFontSet *fs;
       
   166 		FcResult  result;
       
   167 		char *font_style;
       
   168 		char *font_family;
       
   169 
       
   170 		/* Split & strip the font's style */
       
   171 		font_family = strdup(font_name);
       
   172 		font_style = strchr(font_family, ',');
       
   173 		if (font_style != NULL) {
       
   174 			font_style[0] = '\0';
       
   175 			font_style++;
       
   176 			while (*font_style == ' ' || *font_style == '\t') font_style++;
       
   177 		}
       
   178 
       
   179 		/* Resolve the name and populate the information structure */
       
   180 		pat = FcNameParse((FcChar8*)font_family);
       
   181 		if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
       
   182 		FcConfigSubstitute(0, pat, FcMatchPattern);
       
   183 		FcDefaultSubstitute(pat);
       
   184 		fs = FcFontSetCreate();
       
   185 		match = FcFontMatch(0, pat, &result);
       
   186 
       
   187 		if (fs != NULL && match != NULL) {
       
   188 			int i;
       
   189 			FcChar8 *family;
       
   190 			FcChar8 *style;
       
   191 			FcChar8 *file;
       
   192 			FcFontSetAdd(fs, match);
       
   193 
       
   194 			for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
       
   195 				/* Try the new filename */
       
   196 				if (FcPatternGetString(fs->fonts[i], FC_FILE,   0, &file)   == FcResultMatch &&
       
   197 						FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
       
   198 						FcPatternGetString(fs->fonts[i], FC_STYLE,  0, &style)  == FcResultMatch) {
       
   199 
       
   200 					/* The correct style? */
       
   201 					if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
       
   202 
       
   203 					/* Font config takes the best shot, which, if the family name is spelled
       
   204 					* wrongly a 'random' font, so check whether the family name is the
       
   205 					* same as the supplied name */
       
   206 					if (strcasecmp(font_family, (char*)family) == 0) {
       
   207 						err = FT_New_Face(_library, (char *)file, 0, face);
       
   208 					}
       
   209 				}
       
   210 			}
       
   211 		}
       
   212 
       
   213 		free(font_family);
       
   214 		FcPatternDestroy(pat);
       
   215 		FcFontSetDestroy(fs);
       
   216 		FcFini();
       
   217 	}
       
   218 
       
   219 	return err;
       
   220 }
       
   221 # else
       
   222 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
       
   223 # endif /* WITH_FONTCONFIG */
       
   224 
       
   225 #endif
       
   226 
       
   227 /**
       
   228  * Loads the freetype font.
       
   229  * First type to load the fontname as if it were a path. If that fails,
       
   230  * try to resolve the filename of the font using fontconfig, where the
       
   231  * format is 'font family name' or 'font family name, font style'.
       
   232  */
       
   233 static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
       
   234 {
       
   235 	FT_Error error;
       
   236 
       
   237 	if (strlen(font_name) == 0) return;
       
   238 
       
   239 	error = FT_New_Face(_library, font_name, 0, face);
       
   240 
       
   241 	if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, face);
       
   242 
       
   243 	if (error == FT_Err_Ok) {
       
   244 		DEBUG(freetype, 2, "Requested '%s', using '%s %s'", font_name, (*face)->family_name, (*face)->style_name);
       
   245 
       
   246 		/* Attempt to select the unicode character map */
       
   247 		error = FT_Select_Charmap(*face, ft_encoding_unicode);
       
   248 		if (error == FT_Err_Ok) return; // Success
       
   249 
       
   250 		if (error == FT_Err_Invalid_CharMap_Handle) {
       
   251 			/* Try to pick a different character map instead. We default to
       
   252 			 * the first map, but platform_id 0 encoding_id 0 should also
       
   253 			 * be unicode (strange system...) */
       
   254 			FT_CharMap found = (*face)->charmaps[0];
       
   255 			int i;
       
   256 
       
   257 			for (i = 0; i < (*face)->num_charmaps; i++) {
       
   258 				FT_CharMap charmap = (*face)->charmaps[i];
       
   259 				if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
       
   260 					found = charmap;
       
   261 				}
       
   262 			}
       
   263 
       
   264 			if (found != NULL) {
       
   265 				error = FT_Set_Charmap(*face, found);
       
   266 				if (error == FT_Err_Ok) return;
       
   267 			}
       
   268 		}
       
   269 	}
       
   270 
       
   271 	FT_Done_Face(*face);
       
   272 	*face = NULL;
       
   273 
       
   274 	ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
       
   275 }
       
   276 
       
   277 
       
   278 void InitFreeType(void)
       
   279 {
       
   280 	if (strlen(_freetype.small_font) == 0 && strlen(_freetype.medium_font) == 0 && strlen(_freetype.large_font) == 0) {
       
   281 		DEBUG(freetype, 1, "No font faces specified, using sprite fonts instead");
       
   282 		return;
       
   283 	}
       
   284 
       
   285 	if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
       
   286 		ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
       
   287 		return;
       
   288 	}
       
   289 
       
   290 	DEBUG(freetype, 2, "Initialized");
       
   291 
       
   292 	/* Load each font */
       
   293 	LoadFreeTypeFont(_freetype.small_font,  &_face_small,  "small");
       
   294 	LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
       
   295 	LoadFreeTypeFont(_freetype.large_font,  &_face_large,  "large");
       
   296 
       
   297 	/* Set each font size */
       
   298 	if (_face_small  != NULL) FT_Set_Pixel_Sizes(_face_small,  0, _freetype.small_size);
       
   299 	if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
       
   300 	if (_face_large  != NULL) FT_Set_Pixel_Sizes(_face_large,  0, _freetype.large_size);
       
   301 }
       
   302 
       
   303 
       
   304 static FT_Face GetFontFace(FontSize size)
       
   305 {
       
   306 	switch (size) {
       
   307 		default: NOT_REACHED();
       
   308 		case FS_NORMAL: return _face_medium;
       
   309 		case FS_SMALL:  return _face_small;
       
   310 		case FS_LARGE:  return _face_large;
       
   311 	}
       
   312 }
       
   313 
       
   314 
       
   315 typedef struct GlyphEntry {
       
   316 	Sprite *sprite;
       
   317 	byte width;
       
   318 } GlyphEntry;
       
   319 
       
   320 
       
   321 /* The glyph cache. This is structured to reduce memory consumption.
       
   322  * 1) There is a 'segment' table for each font size.
       
   323  * 2) Each segment table is a discrete block of characters.
       
   324  * 3) Each block contains 256 (aligned) characters sequential characters.
       
   325  *
       
   326  * The cache is accessed in the following way:
       
   327  * For character 0x0041  ('A'): _glyph_ptr[FS_NORMAL][0x00][0x41]
       
   328  * For character 0x20AC (Euro): _glyph_ptr[FS_NORMAL][0x20][0xAC]
       
   329  *
       
   330  * Currently only 256 segments are allocated, "limiting" us to 65536 characters.
       
   331  * This can be simply changed in the two functions Get & SetGlyphPtr.
       
   332  */
       
   333 static GlyphEntry **_glyph_ptr[FS_END];
       
   334 
       
   335 
       
   336 static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
       
   337 {
       
   338 	if (_glyph_ptr[size] == NULL) return NULL;
       
   339 	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
       
   340 	return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
       
   341 }
       
   342 
       
   343 
       
   344 static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
       
   345 {
       
   346 	if (_glyph_ptr[size] == NULL) {
       
   347 		DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
       
   348 		_glyph_ptr[size] = calloc(256, sizeof(**_glyph_ptr));
       
   349 	}
       
   350 
       
   351 	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
       
   352 		DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
       
   353 		_glyph_ptr[size][GB(key, 8, 8)] = calloc(256, sizeof(***_glyph_ptr));
       
   354 	}
       
   355 
       
   356 	DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
       
   357 	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
       
   358 	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width  = glyph->width;
       
   359 }
       
   360 
       
   361 
       
   362 const Sprite *GetGlyph(FontSize size, WChar key)
       
   363 {
       
   364 	FT_Face face = GetFontFace(size);
       
   365 	FT_GlyphSlot slot;
       
   366 	GlyphEntry new_glyph;
       
   367 	GlyphEntry *glyph;
       
   368 	Sprite *sprite;
       
   369 	int width;
       
   370 	int height;
       
   371 	int x;
       
   372 	int y;
       
   373 	int y_adj;
       
   374 
       
   375 	assert(IsPrintable(key));
       
   376 
       
   377 	/* Bail out if no face loaded, or for our special characters */
       
   378 	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
       
   379 		SpriteID sprite = GetUnicodeGlyph(size, key);
       
   380 		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
       
   381 		return GetSprite(sprite);
       
   382 	}
       
   383 
       
   384 	/* Check for the glyph in our cache */
       
   385 	glyph = GetGlyphPtr(size, key);
       
   386 	if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
       
   387 
       
   388 	slot = face->glyph;
       
   389 
       
   390 	FT_Load_Char(face, key, FT_LOAD_DEFAULT);
       
   391 	FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
       
   392 
       
   393 	/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
       
   394 	width  = max(1, slot->bitmap.width + (size == FS_NORMAL));
       
   395 	height = max(1, slot->bitmap.rows  + (size == FS_NORMAL));
       
   396 
       
   397 	/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
       
   398 	sprite = calloc(width * height + 8, 1);
       
   399 	sprite->info   = 1;
       
   400 	sprite->width  = width;
       
   401 	sprite->height = height;
       
   402 	sprite->x_offs = slot->bitmap_left;
       
   403 	// XXX 2 should be determined somehow... it's right for the normal face
       
   404 	y_adj = (size == FS_NORMAL) ? 2 : 0;
       
   405 	sprite->y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
       
   406 
       
   407 	/* Draw shadow for medium size */
       
   408 	if (size == FS_NORMAL) {
       
   409 		for (y = 0; y < slot->bitmap.rows; y++) {
       
   410 			for (x = 0; x < slot->bitmap.width; x++) {
       
   411 				if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
       
   412 					sprite->data[1 + x + (1 + y) * sprite->width] = SHADOW_COLOUR;
       
   413 				}
       
   414 			}
       
   415 		}
       
   416 	}
       
   417 
       
   418 	for (y = 0; y < slot->bitmap.rows; y++) {
       
   419 		for (x = 0; x < slot->bitmap.width; x++) {
       
   420 			if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
       
   421 				sprite->data[x + y * sprite->width] = FACE_COLOUR;
       
   422 			}
       
   423 		}
       
   424 	}
       
   425 
       
   426 	new_glyph.sprite = sprite;
       
   427 	new_glyph.width  = (slot->advance.x >> 6) + (size != FS_NORMAL);
       
   428 
       
   429 	SetGlyphPtr(size, key, &new_glyph);
       
   430 
       
   431 	return sprite;
       
   432 }
       
   433 
       
   434 
       
   435 uint GetGlyphWidth(FontSize size, WChar key)
       
   436 {
       
   437 	FT_Face face = GetFontFace(size);
       
   438 	GlyphEntry *glyph;
       
   439 
       
   440 	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
       
   441 		SpriteID sprite = GetUnicodeGlyph(size, key);
       
   442 		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
       
   443 		return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
       
   444 	}
       
   445 
       
   446 	glyph = GetGlyphPtr(size, key);
       
   447 	if (glyph == NULL || glyph->sprite == NULL) {
       
   448 		GetGlyph(size, key);
       
   449 		glyph = GetGlyphPtr(size, key);
       
   450 	}
       
   451 
       
   452 	return glyph->width;
       
   453 }
       
   454 
       
   455 
       
   456 #endif /* WITH_FREETYPE */
       
   457 
       
   458 /* Sprite based glyph mapping */
       
   459 
       
   460 #include "table/unicode.h"
       
   461 
       
   462 static SpriteID **_unicode_glyph_map[FS_END];
       
   463 
       
   464 
       
   465 /** Get the SpriteID of the first glyph for the given font size */
       
   466 static SpriteID GetFontBase(FontSize size)
       
   467 {
       
   468 	switch (size) {
       
   469 		default: NOT_REACHED();
       
   470 		case FS_NORMAL: return SPR_ASCII_SPACE;
       
   471 		case FS_SMALL:  return SPR_ASCII_SPACE_SMALL;
       
   472 		case FS_LARGE:  return SPR_ASCII_SPACE_BIG;
       
   473 	}
       
   474 }
       
   475 
       
   476 
       
   477 SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
       
   478 {
       
   479 	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
       
   480 	return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
       
   481 }
       
   482 
       
   483 
       
   484 void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
       
   485 {
       
   486 	if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = calloc(256, sizeof(*_unicode_glyph_map[size]));
       
   487 	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = calloc(256, sizeof(**_unicode_glyph_map[size]));
       
   488 	_unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
       
   489 }
       
   490 
       
   491 
       
   492 void InitializeUnicodeGlyphMap(void)
       
   493 {
       
   494 	FontSize size;
       
   495 	SpriteID base;
       
   496 	SpriteID sprite;
       
   497 	uint i;
       
   498 
       
   499 	for (size = FS_NORMAL; size != FS_END; size++) {
       
   500 		/* Clear out existing glyph map if it exists */
       
   501 		if (_unicode_glyph_map[size] != NULL) {
       
   502 			for (i = 0; i < 256; i++) {
       
   503 				if (_unicode_glyph_map[size][i] != NULL) free(_unicode_glyph_map[size][i]);
       
   504 			}
       
   505 			free(_unicode_glyph_map[size]);
       
   506 			_unicode_glyph_map[size] = NULL;
       
   507 		}
       
   508 
       
   509 		base = GetFontBase(size);
       
   510 		for (i = ASCII_LETTERSTART; i < 256; i++) {
       
   511 			sprite = base + i - ASCII_LETTERSTART;
       
   512 			if (!SpriteExists(sprite)) continue;
       
   513 			SetUnicodeGlyph(size, i, sprite);
       
   514 			SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
       
   515 		}
       
   516 		for (i = 0; i < lengthof(_default_unicode_map); i++) {
       
   517 			sprite = base + _default_unicode_map[i].key - ASCII_LETTERSTART;
       
   518 			SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
       
   519 		}
       
   520 	}
       
   521 }
       
   522 
       
   523 
       
   524