Changeset - r28452:36c20baf9fe4
[Not reviewed]
master
0 8 5
Michael Lutz - 4 months ago 2023-12-16 00:03:28
michi@icosahedron.de
Feature: Scalable OpenTTD TrueType font made by Zephyris.

This uses the normal variant for the small font, not the all-caps version.
13 files changed with 259 insertions and 112 deletions:
0 comments (0 inline, 0 general)
CREDITS.md
Show inline comments
 
@@ -56,6 +56,7 @@
 
- George - Canal/Lock graphics
 
- Andrew Parkhouse (andythenorth) - River graphics
 
- David Dallaston (Pikka) - Tram tracks
 
- Richard Wheeler (zephyris) - OpenTTD TrueType font
 
- All Translators - For their support to make OpenTTD a truly international game
 
- Bug Reporters - Thanks for all bug reports
 
- Chris Sawyer - For an amazing game!
media/baseset/CMakeLists.txt
Show inline comments
 
@@ -18,6 +18,10 @@ set(BASESET_OTHER_SOURCE_FILES
 
        ${CMAKE_CURRENT_SOURCE_DIR}/opntitle.dat
 
        ${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf
 
        ${CMAKE_CURRENT_SOURCE_DIR}/../openttd.32.bmp
 
        ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Sans.ttf
 
        ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Serif.ttf
 
        ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Small.ttf
 
        ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Mono.ttf
 
)
 

	
 
# Done by the subdirectories, if nforenum / grfcodec is installed
media/baseset/OpenTTD-Mono.ttf
Show inline comments
 
new file 100644
 
binary diff not shown
media/baseset/OpenTTD-Sans.ttf
Show inline comments
 
new file 100644
 
binary diff not shown
media/baseset/OpenTTD-Serif.ttf
Show inline comments
 
new file 100644
 
binary diff not shown
media/baseset/OpenTTD-Small.ttf
Show inline comments
 
new file 100644
 
binary diff not shown
media/baseset/OpenTTD-font.md
Show inline comments
 
new file 100644
 
# OpenTTD TrueType font
 

	
 
The OpenTTD TrueType font was created by Zephyris and is maintained on [Github](https://github.com/zephyris/openttd-ttf).
 
It is licensed under GPL-2.0.
 

	
 
The currently included files correspond to release v0.3.
src/fontcache.cpp
Show inline comments
 
@@ -18,6 +18,7 @@
 
#include "strings_func.h"
 
#include "viewport_func.h"
 
#include "window_func.h"
 
#include "fileio_func.h"
 

	
 
#include "safeguards.h"
 

	
 
@@ -143,13 +144,52 @@ void SetFont(FontSize fontsize, const st
 

	
 
#ifdef WITH_FREETYPE
 
extern void LoadFreeTypeFont(FontSize fs);
 
extern void LoadFreeTypeFont(FontSize fs, const std::string &file_name, uint size);
 
extern void UninitFreeType();
 
#elif defined(_WIN32)
 
extern void LoadWin32Font(FontSize fs);
 
extern void LoadWin32Font(FontSize fs, const std::string &file_name, uint size);
 
#elif defined(WITH_COCOA)
 
extern void LoadCoreTextFont(FontSize fs);
 
extern void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size);
 
#endif
 

	
 
static void TryLoadDefaultTrueTypeFont([[maybe_unused]] FontSize fs)
 
{
 
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
 
	std::string font_name{};
 
	switch (fs) {
 
		case FS_NORMAL:
 
			font_name = "OpenTTD-Sans.ttf";
 
			break;
 
		case FS_SMALL:
 
			font_name = "OpenTTD-Small.ttf";
 
			break;
 
		case FS_LARGE:
 
			font_name = "OpenTTD-Serif.ttf";
 
			break;
 
		case FS_MONO:
 
			font_name = "OpenTTD-Mono.ttf";
 
			break;
 

	
 
		default: NOT_REACHED();
 
	}
 

	
 
	/* Find font file. */
 
	std::string full_font = FioFindFullPath(BASESET_DIR, font_name);
 
	if (!full_font.empty()) {
 
		int size = FontCache::GetDefaultFontHeight(fs);
 
#ifdef WITH_FREETYPE
 
		LoadFreeTypeFont(fs, full_font, size);
 
#elif defined(_WIN32)
 
		LoadWin32Font(fs, full_font, size);
 
#elif defined(WITH_COCOA)
 
		LoadCoreTextFont(fs, full_font, size);
 
#endif
 
	}
 
#endif /* defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) */
 
}
 

	
 
/**
 
 * (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
 
 * @param monospace Whether to initialise the monospace or regular fonts.
 
@@ -164,13 +204,17 @@ void InitFontCache(bool monospace)
 
		FontCache *fc = FontCache::Get(fs);
 
		if (fc->HasParent()) delete fc;
 

	
 
		if (GetFontCacheSubSetting(fs)->font.empty()) {
 
			TryLoadDefaultTrueTypeFont(fs);
 
		} else {
 
#ifdef WITH_FREETYPE
 
		LoadFreeTypeFont(fs);
 
			LoadFreeTypeFont(fs);
 
#elif defined(_WIN32)
 
		LoadWin32Font(fs);
 
			LoadWin32Font(fs);
 
#elif defined(WITH_COCOA)
 
		LoadCoreTextFont(fs);
 
			LoadCoreTextFont(fs);
 
#endif
 
		}
 
	}
 
}
 

	
src/fontcache/freetypefontcache.cpp
Show inline comments
 
@@ -115,6 +115,42 @@ void FreeTypeFontCache::SetFontSize(Font
 
	}
 
}
 

	
 
static FT_Error LoadFont(FontSize fs, FT_Face face, const char *font_name, uint size)
 
{
 
	Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
 

	
 
	/* Attempt to select the unicode character map */
 
	FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
 
	if (error == FT_Err_Ok) goto found_face; // Success
 

	
 
	if (error == FT_Err_Invalid_CharMap_Handle) {
 
		/* Try to pick a different character map instead. We default to
 
		 * the first map, but platform_id 0 encoding_id 0 should also
 
		 * be unicode (strange system...) */
 
		FT_CharMap found = face->charmaps[0];
 
		int i;
 

	
 
		for (i = 0; i < face->num_charmaps; i++) {
 
			FT_CharMap charmap = face->charmaps[i];
 
			if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
 
				found = charmap;
 
			}
 
		}
 

	
 
		if (found != nullptr) {
 
			error = FT_Set_Charmap(face, found);
 
			if (error == FT_Err_Ok) goto found_face;
 
		}
 
	}
 

	
 
	FT_Done_Face(face);
 
	return error;
 

	
 
found_face:
 
	new FreeTypeFontCache(fs, face, size);
 
	return FT_Err_Ok;
 
}
 

	
 
/**
 
 * Loads the freetype font.
 
 * First type to load the fontname as if it were a path. If that fails,
 
@@ -157,40 +193,40 @@ void LoadFreeTypeFont(FontSize fs)
 
	if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, &face);
 

	
 
	if (error == FT_Err_Ok) {
 
		Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
 

	
 
		/* Attempt to select the unicode character map */
 
		error = FT_Select_Charmap(face, ft_encoding_unicode);
 
		if (error == FT_Err_Ok) goto found_face; // Success
 

	
 
		if (error == FT_Err_Invalid_CharMap_Handle) {
 
			/* Try to pick a different character map instead. We default to
 
			 * the first map, but platform_id 0 encoding_id 0 should also
 
			 * be unicode (strange system...) */
 
			FT_CharMap found = face->charmaps[0];
 
			int i;
 
		error = LoadFont(fs, face, font_name, settings->size);
 
		if (error != FT_Err_Ok) {
 
			ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
 
		}
 
	} else {
 
		FT_Done_Face(face);
 
	}
 
}
 

	
 
			for (i = 0; i < face->num_charmaps; i++) {
 
				FT_CharMap charmap = face->charmaps[i];
 
				if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
 
					found = charmap;
 
				}
 
			}
 
/**
 
 * Load a TrueType font from a file.
 
 * @param fs The font size to load.
 
 * @param file_name Path to the font file.
 
 * @param size Requested font size.
 
 */
 
void LoadFreeTypeFont(FontSize fs, const std::string &file_name, uint size)
 
{
 
	if (_library == nullptr) {
 
		if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
 
			ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
 
			return;
 
		}
 

	
 
			if (found != nullptr) {
 
				error = FT_Set_Charmap(face, found);
 
				if (error == FT_Err_Ok) goto found_face;
 
			}
 
		}
 
		Debug(fontcache, 2, "Initialized");
 
	}
 

	
 
	FT_Done_Face(face);
 

	
 
	ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
 
	return;
 

	
 
found_face:
 
	new FreeTypeFontCache(fs, face, settings->size);
 
	FT_Face face = nullptr;
 
	int32_t index = 0;
 
	FT_Error error = FT_New_Face(_library, file_name.c_str(), index, &face);
 
	if (error == FT_Err_Ok) {
 
		LoadFont(fs, face, file_name.c_str(), size);
 
	} else {
 
		FT_Done_Face(face);
 
	}
 
}
 

	
 

	
src/os/macosx/font_osx.cpp
Show inline comments
 
@@ -298,6 +298,40 @@ const Sprite *CoreTextFontCache::Interna
 
	return new_glyph.sprite;
 
}
 

	
 
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
 
{
 
	if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
 

	
 
	/* Might be a font file name, try load it. Direct font loading is
 
	 * only supported starting on OSX 10.6. */
 
	CFAutoRelease<CFStringRef> path;
 

	
 
	/* See if this is an absolute path. */
 
	if (FileExists(font_name)) {
 
		path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
 
	} else {
 
		/* Scan the search-paths to see if it can be found. */
 
		std::string full_font = FioFindFullPath(BASE_DIR, font_name);
 
		if (!full_font.empty()) {
 
			path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
 
		}
 
	}
 

	
 
	if (path) {
 
		/* Try getting a font descriptor to see if the system can use it. */
 
		CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
 
		CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
 

	
 
		if (descs && CFArrayGetCount(descs.get()) > 0) {
 
			CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
 
			CFRetain(font_ref);
 
			return font_ref;
 
		}
 
	}
 

	
 
	return nullptr;
 
}
 

	
 
/**
 
 * Loads the TrueType font.
 
 * If a CoreText font description is present, e.g. from the automatic font
 
@@ -318,33 +352,9 @@ void LoadCoreTextFont(FontSize fs)
 
	}
 

	
 
	if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
 
		/* Might be a font file name, try load it. Direct font loading is
 
		 * only supported starting on OSX 10.6. */
 
		CFAutoRelease<CFStringRef> path;
 

	
 
		/* See if this is an absolute path. */
 
		if (FileExists(settings->font)) {
 
			path.reset(CFStringCreateWithCString(kCFAllocatorDefault, settings->font.c_str(), kCFStringEncodingUTF8));
 
		} else {
 
			/* Scan the search-paths to see if it can be found. */
 
			std::string full_font = FioFindFullPath(BASE_DIR, settings->font);
 
			if (!full_font.empty()) {
 
				path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
 
			}
 
		}
 

	
 
		if (path) {
 
			/* Try getting a font descriptor to see if the system can use it. */
 
			CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
 
			CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
 

	
 
			if (descs && CFArrayGetCount(descs.get()) > 0) {
 
				font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
 
				CFRetain(font_ref.get());
 
			} else {
 
				ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", settings->font, FontSizeToName(fs));
 
			}
 
		}
 
		/* Might be a font file name, try load it. */
 
		font_ref.reset(LoadFontFromFile(settings->font));
 
		if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", settings->font, FontSizeToName(fs));
 
	}
 

	
 
	if (!font_ref) {
 
@@ -372,3 +382,17 @@ void LoadCoreTextFont(FontSize fs)
 

	
 
	new CoreTextFontCache(fs, std::move(font_ref), settings->size);
 
}
 

	
 
/**
 
 * Load a TrueType font from a file.
 
 * @param fs The font size to load.
 
 * @param file_name Path to the font file.
 
 * @param size Requested font size.
 
 */
 
void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size)
 
{
 
	CFAutoRelease<CTFontDescriptorRef> font_ref{LoadFontFromFile(file_name)};
 
	if (font_ref) {
 
		new CoreTextFontCache(fs, std::move(font_ref), size);
 
	}
 
}
src/os/macosx/font_osx.h
Show inline comments
 
@@ -36,5 +36,6 @@ public:
 
};
 

	
 
void LoadCoreTextFont(FontSize fs);
 
void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size);
 

	
 
#endif /* FONT_OSX_H */
src/os/windows/font_win32.cpp
Show inline comments
 
@@ -317,6 +317,66 @@ void Win32FontCache::ClearFontCache()
 
}
 

	
 

	
 
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
 
{
 
	wchar_t fontPath[MAX_PATH] = {};
 

	
 
	/* See if this is an absolute path. */
 
	if (FileExists(font_name)) {
 
		convert_to_fs(font_name, fontPath, lengthof(fontPath));
 
	} else {
 
		/* Scan the search-paths to see if it can be found. */
 
		std::string full_font = FioFindFullPath(BASE_DIR, font_name);
 
		if (!full_font.empty()) {
 
			convert_to_fs(font_name, fontPath, lengthof(fontPath));
 
		}
 
	}
 

	
 
	if (fontPath[0] != 0) {
 
		if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
 
			/* Try a nice little undocumented function first for getting the internal font name.
 
			 * Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
 
			static LibraryLoader _gdi32("gdi32.dll");
 
			typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
 
			static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
 

	
 
			if (GetFontResourceInfo != nullptr) {
 
				/* Try to query an array of LOGFONTs that describe the file. */
 
				DWORD len = 0;
 
				if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
 
					LOGFONT *buf = (LOGFONT *)new byte[len];
 
					if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
 
						logfont = *buf; // Just use first entry.
 
					}
 
					delete[](byte *)buf;
 
				}
 
			}
 

	
 
			/* No dice yet. Use the file name as the font face name, hoping it matches. */
 
			if (logfont.lfFaceName[0] == 0) {
 
				wchar_t fname[_MAX_FNAME];
 
				_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
 

	
 
				wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
 
				logfont.lfWeight = strcasestr(font_name.c_str(), " bold") != nullptr || strcasestr(font_name.c_str(), "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
 
			}
 
		}
 
	}
 

	
 
	return logfont.lfFaceName[0] != 0;
 
}
 

	
 
static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, const char *font_name)
 
{
 
	HFONT font = CreateFontIndirect(&logfont);
 
	if (font == nullptr) {
 
		ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
 
		return;
 
	}
 
	DeleteObject(font);
 

	
 
	new Win32FontCache(fs, logfont, size);
 
}
 
/**
 
 * Loads the GDI font.
 
 * If a GDI font description is present, e.g. from the automatic font
 
@@ -341,51 +401,8 @@ void LoadWin32Font(FontSize fs)
 
		logfont = *(const LOGFONT *)settings->os_handle;
 
	} else if (strchr(font_name, '.') != nullptr) {
 
		/* Might be a font file name, try load it. */
 

	
 
		wchar_t fontPath[MAX_PATH] = {};
 

	
 
		/* See if this is an absolute path. */
 
		if (FileExists(settings->font)) {
 
			convert_to_fs(font_name, fontPath, lengthof(fontPath));
 
		} else {
 
			/* Scan the search-paths to see if it can be found. */
 
			std::string full_font = FioFindFullPath(BASE_DIR, font_name);
 
			if (!full_font.empty()) {
 
				convert_to_fs(font_name, fontPath, lengthof(fontPath));
 
			}
 
		}
 

	
 
		if (fontPath[0] != 0) {
 
			if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
 
				/* Try a nice little undocumented function first for getting the internal font name.
 
				 * Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
 
				static LibraryLoader _gdi32("gdi32.dll");
 
				typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
 
				static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
 

	
 
				if (GetFontResourceInfo != nullptr) {
 
					/* Try to query an array of LOGFONTs that describe the file. */
 
					DWORD len = 0;
 
					if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
 
						LOGFONT *buf = (LOGFONT *)new byte[len];
 
						if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
 
							logfont = *buf; // Just use first entry.
 
						}
 
						delete[] (byte *)buf;
 
					}
 
				}
 

	
 
				/* No dice yet. Use the file name as the font face name, hoping it matches. */
 
				if (logfont.lfFaceName[0] == 0) {
 
					wchar_t fname[_MAX_FNAME];
 
					_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
 

	
 
					wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
 
					logfont.lfWeight = strcasestr(font_name, " bold") != nullptr || strcasestr(font_name, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
 
				}
 
			} else {
 
				ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font_name, FontSizeToName(fs));
 
			}
 
		if (!TryLoadFontFromFile(settings->font, logfont)) {
 
			ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font_name, FontSizeToName(fs));
 
		}
 
	}
 

	
 
@@ -394,12 +411,25 @@ void LoadWin32Font(FontSize fs)
 
		convert_to_fs(font_name, logfont.lfFaceName, lengthof(logfont.lfFaceName));
 
	}
 

	
 
	HFONT font = CreateFontIndirect(&logfont);
 
	if (font == nullptr) {
 
		ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
 
		return;
 
	LoadWin32Font(fs, logfont, settings->size, font_name);
 
}
 

	
 
/**
 
 * Load a TrueType font from a file.
 
 * @param fs The font size to load.
 
 * @param file_name Path to the font file.
 
 * @param size Requested font size.
 
 */
 
void LoadWin32Font(FontSize fs, const std::string &file_name, uint size)
 
{
 
	LOGFONT logfont;
 
	MemSetT(&logfont, 0);
 
	logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
 
	logfont.lfCharSet = DEFAULT_CHARSET;
 
	logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
 
	logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 

	
 
	if (TryLoadFontFromFile(file_name, logfont)) {
 
		LoadWin32Font(fs, logfont, size, file_name.c_str());
 
	}
 
	DeleteObject(font);
 

	
 
	new Win32FontCache(fs, logfont, settings->size);
 
}
src/os/windows/font_win32.h
Show inline comments
 
@@ -41,5 +41,6 @@ public:
 
};
 

	
 
void LoadWin32Font(FontSize fs);
 
void LoadWin32Font(FontSize fs, const std::string &file_name, uint size);
 

	
 
#endif /* FONT_WIN32_H */
0 comments (0 inline, 0 general)