Merge branch 'master' into jgrpp

# Conflicts:
#	src/fontcache.cpp
#	src/openttd.cpp
#	src/os/macosx/font_osx.cpp
#	src/os/unix/font_unix.cpp
#	src/os/windows/font_win32.cpp
#	src/strings.cpp
pull/441/head
Jonathan G Rennison 2 years ago
commit 23b974fb39

@ -94,8 +94,8 @@ Although we really appreciate feedback and ideas, we will close feature requests
Many of those ideas etc do have a place on the [forums](https://www.tt-forums.net); and if enough people like it, someone will stand up and make it.
It's usually best discuss in [irc](https://wiki.openttd.org/en/Development/IRC%20channel) before opening a feature request or working on a large feature in a fork.
Discussion in irc can take time, but it can be productive and avoid disappointment :)
It's usually best to discuss on [Discord](https://discord.gg/openttd) before opening a feature request or working on a large feature in a fork.
Discussion can take time, but it can be productive and avoid disappointment. :)
## Pull requests

@ -493,35 +493,6 @@ Most types of add-on content can be downloaded within OpenTTD via the 'Check Onl
Add-on content can also be installed manually, but that's more complicated; the [OpenTTD wiki](https://wiki.openttd.org/) may offer help with that, or the [OpenTTD directory structure guide](./docs/directory_structure.md).
### 1.5.1) AI opponents
OpenTTD comes without AI opponents, so if you want to play with AIs you have to download them.
The easiest way is via the 'Check Online Content' button in the main menu.
You can select some AIs that you think are compatible with your playing style.
AI help and discussions may also be found in the [AI section of the forum](https://www.tt-forums.net/viewforum.php?f=65).
### 1.5.2) Scenarios and height maps
Scenarios and heightmaps can be added via the 'Check Online Content' button in the main menu.
### 1.5.3) NewGRFs
A wide range of add-content is available as NewGRFs, including vehicles, industries, stations, landscape objects, town names and more.
NewGRFs can be added via the 'Check Online Content' button in the main menu.
See also the wiki [guide to NewGRFs](https://wiki.openttd.org/en/Manual/NewGRF) and [the forum graphics development section](https://www.tt-forums.net/viewforum.php?f=66).
### 1.5.4) Game scripts
Game scripts can provide additional challenges or changes to the standard OpenTTD gameplay, for example setting transport goals, or changing town growth behaviour.
Game scripts can be added via the 'Check Online Content' button in the main menu.
See also the wiki [guide to game scripts](https://wiki.openttd.org/en/Manual/Game%20script) and [the forum graphics game script section](https://www.tt-forums.net/viewforum.php?f=65).
### 1.6) OpenTTD directories
@ -539,6 +510,7 @@ If you want to compile OpenTTD from source, instructions can be found in [COMPIL
'Official' channels
- [OpenTTD website](https://www.openttd.org)
- [OpenTTD official Discord](https://discord.gg/openttd)
- IRC chat using #openttd on irc.oftc.net [more info about our irc channel](https://wiki.openttd.org/en/Development/IRC%20channel)
- [OpenTTD on Github](https://github.com/OpenTTD/) for code repositories and for reporting issues
- [forum.openttd.org](https://forum.openttd.org/) - the primary community forum site for discussing OpenTTD and related games

@ -3,6 +3,7 @@
source_group("AI Core" REGULAR_EXPRESSION "src/ai/")
source_group("Blitters" REGULAR_EXPRESSION "src/blitter/")
source_group("Core Source Code" REGULAR_EXPRESSION "src/core/")
source_group("Font Cache" REGULAR_EXPRESSION "src/fontcache/")
source_group("Game Core" REGULAR_EXPRESSION "src/game/")
source_group("MD5" REGULAR_EXPRESSION "src/3rdparty/md5/")
source_group("Misc" REGULAR_EXPRESSION "src/misc/")

@ -10,6 +10,7 @@ add_subdirectory(3rdparty)
add_subdirectory(ai)
add_subdirectory(blitter)
add_subdirectory(core)
add_subdirectory(fontcache)
add_subdirectory(game)
add_subdirectory(lang)
add_subdirectory(linkgraph)
@ -162,7 +163,6 @@ add_files(
fios_gui.cpp
fontcache.cpp
fontcache.h
fontcache_internal.h
fontdetection.h
framerate_gui.cpp
framerate_type.h

@ -283,16 +283,16 @@ bool HandleBootstrap()
/* No user interface, bail out with an error. */
if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
/* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */
/* If there is no network or no non-sprite font, then there is nothing we can do. Go straight to failure. */
#if (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA)
if (!_network_available) goto failure;
/* First tell the game we're bootstrapping. */
_game_mode = GM_BOOTSTRAP;
/* Initialise the freetype font code. */
/* Initialise the font cache. */
InitializeUnicodeGlyphMap();
/* Next "force" finding a suitable freetype font as the local font is missing. */
/* Next "force" finding a suitable non-sprite font as the local font is missing. */
CheckForMissingGlyphs(false);
/* Initialise the palette. The biggest step is 'faking' some recolour sprites.

@ -1327,82 +1327,82 @@ static const NWidgetPart _nested_select_company_manager_face_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_WHITE_STRING, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_WHITE_STRING, STR_FACE_GLASSES_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_HAIR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_WHITE_STRING, STR_FACE_HAIR_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EYEBROWS, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_WHITE_STRING, STR_FACE_EYEBROWS_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_WHITE_STRING, STR_FACE_EYECOLOUR_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_WHITE_STRING, STR_FACE_GLASSES_TOOLTIP_2),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_NOSE, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_WHITE_STRING, STR_FACE_NOSE_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_MOUSTACHE, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_WHITE_STRING, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_CHIN, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_WHITE_STRING, STR_FACE_CHIN_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_JACKET, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_WHITE_STRING, STR_FACE_JACKET_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_COLLAR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_WHITE_STRING, STR_FACE_COLLAR_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EARRING, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_WHITE_STRING, STR_FACE_TIE_EARRING_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetFill(0, 1),
@ -1432,29 +1432,26 @@ class SelectCompanyManagerFaceWindow : public Window
Dimension number_dim; ///< Dimension of a number widget of a part in the advanced face window.
/**
* Draw dynamic a label to the left of the button and a value in the button
* Set parameters for value of face control buttons.
*
* @param widget_index index of this widget in the window
* @param val the value which will be draw
* @param val the value which will be displayed
* @param is_bool_widget is it a bool button
*/
void DrawFaceStringLabel(byte widget_index, uint8 val, bool is_bool_widget) const
void SetFaceStringParameters(byte widget_index, uint8 val, bool is_bool_widget) const
{
StringID str;
const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
if (!nwi_widget->IsDisabled()) {
if (nwi_widget->IsDisabled()) {
SetDParam(0, STR_EMPTY);
} else {
if (is_bool_widget) {
/* if it a bool button write yes or no */
str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
SetDParam(0, (val != 0) ? STR_FACE_YES : STR_FACE_NO);
} else {
/* else write the value + 1 */
SetDParam(0, val + 1);
str = STR_JUST_INT;
SetDParam(0, STR_JUST_INT);
SetDParam(1, val + 1);
}
/* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(),
nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER);
}
}
@ -1631,65 +1628,70 @@ public:
this->DrawWidgets();
}
void DrawWidget(const Rect &r, int widget) const override
void SetStringParameters(int widget) const override
{
switch (widget) {
case WID_SCMF_HAS_MOUSTACHE_EARRING:
if (this->is_female) { // Only for female faces
this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
this->SetFaceStringParameters(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
} else { // Only for male faces
this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge), true);
this->SetFaceStringParameters(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge), true);
}
break;
case WID_SCMF_TIE_EARRING:
this->DrawFaceStringLabel(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
break;
case WID_SCMF_LIPS_MOUSTACHE:
if (this->is_moust_male) { // Only for male faces with moustache
this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
} else { // Only for female faces or male faces without moustache
this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS, this->ge), false);
}
break;
case WID_SCMF_HAS_GLASSES:
this->DrawFaceStringLabel(WID_SCMF_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
this->SetFaceStringParameters(WID_SCMF_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
break;
case WID_SCMF_HAIR:
this->DrawFaceStringLabel(WID_SCMF_HAIR, GetCompanyManagerFaceBits(this->face, CMFV_HAIR, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_HAIR, GetCompanyManagerFaceBits(this->face, CMFV_HAIR, this->ge), false);
break;
case WID_SCMF_EYEBROWS:
this->DrawFaceStringLabel(WID_SCMF_EYEBROWS, GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_EYEBROWS, GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS, this->ge), false);
break;
case WID_SCMF_EYECOLOUR:
this->DrawFaceStringLabel(WID_SCMF_EYECOLOUR, GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_EYECOLOUR, GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR, this->ge), false);
break;
case WID_SCMF_GLASSES:
this->DrawFaceStringLabel(WID_SCMF_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_GLASSES, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_GLASSES, this->ge), false);
break;
case WID_SCMF_NOSE:
this->DrawFaceStringLabel(WID_SCMF_NOSE, GetCompanyManagerFaceBits(this->face, CMFV_NOSE, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_NOSE, GetCompanyManagerFaceBits(this->face, CMFV_NOSE, this->ge), false);
break;
case WID_SCMF_CHIN:
this->DrawFaceStringLabel(WID_SCMF_CHIN, GetCompanyManagerFaceBits(this->face, CMFV_CHIN, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_CHIN, GetCompanyManagerFaceBits(this->face, CMFV_CHIN, this->ge), false);
break;
case WID_SCMF_JACKET:
this->DrawFaceStringLabel(WID_SCMF_JACKET, GetCompanyManagerFaceBits(this->face, CMFV_JACKET, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_JACKET, GetCompanyManagerFaceBits(this->face, CMFV_JACKET, this->ge), false);
break;
case WID_SCMF_COLLAR:
this->DrawFaceStringLabel(WID_SCMF_COLLAR, GetCompanyManagerFaceBits(this->face, CMFV_COLLAR, this->ge), false);
this->SetFaceStringParameters(WID_SCMF_COLLAR, GetCompanyManagerFaceBits(this->face, CMFV_COLLAR, this->ge), false);
break;
}
}
void DrawWidget(const Rect &r, int widget) const override
{
switch (widget) {
case WID_SCMF_FACE:
DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top);
break;

@ -56,7 +56,7 @@ int _debug_sprite_level;
int _debug_oldloader_level;
int _debug_npf_level;
int _debug_yapf_level;
int _debug_freetype_level;
int _debug_fontcache_level;
int _debug_script_level;
int _debug_sl_level;
int _debug_gamelog_level;
@ -93,7 +93,7 @@ struct DebugLevel {
DEBUG_LEVEL(oldloader),
DEBUG_LEVEL(npf),
DEBUG_LEVEL(yapf),
DEBUG_LEVEL(freetype),
DEBUG_LEVEL(fontcache),
DEBUG_LEVEL(script),
DEBUG_LEVEL(sl),
DEBUG_LEVEL(gamelog),

@ -44,7 +44,7 @@ extern int _debug_sprite_level;
extern int _debug_oldloader_level;
extern int _debug_npf_level;
extern int _debug_yapf_level;
extern int _debug_freetype_level;
extern int _debug_fontcache_level;
extern int _debug_script_level;
extern int _debug_sl_level;
extern int _debug_gamelog_level;

@ -735,11 +735,8 @@ public:
}
}
void OnMouseLoop() override
void OnMouseOver(Point pt, int widget) override
{
const Point pt{ _cursor.pos.x - this->left, _cursor.pos.y - this->top };
const int widget = GetWidgetFromPos(this, pt.x, pt.y);
if (widget == WID_SL_DRIVES_DIRECTORIES_LIST) {
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WD_FRAMERECT_TOP);
if (y == INT_MAX) return;

@ -9,30 +9,18 @@
#include "stdafx.h"
#include "fontcache.h"
#include "fontcache_internal.h"
#include "fontdetection.h"
#include "blitter/factory.hpp"
#include "core/math_func.hpp"
#include "core/smallmap_type.hpp"
#include "strings_func.h"
#include "zoom_type.h"
#include "gfx_layout.h"
#include "zoom_func.h"
#include "fileio_func.h"
#include "table/sprites.h"
#include "table/control_codes.h"
#include "table/unicode.h"
#include "fontcache/spritefontcache.h"
#include "safeguards.h"
static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter.
/** Default heights for the different sizes of fonts. */
static const int _default_font_height[FS_END] = {10, 6, 18, 10};
static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
FreeTypeSettings _freetype;
FontCacheSettings _fcsettings;
/**
* Create a new font cache.
@ -61,134 +49,6 @@ int FontCache::GetDefaultFontHeight(FontSize fs)
return _default_font_height[fs];
}
/** Font cache for fonts that are based on a freetype font. */
class SpriteFontCache : public FontCache {
private:
SpriteID **glyph_to_spriteid_map; ///< Mapping of glyphs to sprite IDs.
void ClearGlyphToSpriteMap();
public:
SpriteFontCache(FontSize fs);
~SpriteFontCache();
SpriteID GetUnicodeGlyph(WChar key) override;
void SetUnicodeGlyph(WChar key, SpriteID sprite) override;
void InitializeUnicodeGlyphMap() override;
void ClearFontCache() override;
const Sprite *GetGlyph(GlyphID key) override;
uint GetGlyphWidth(GlyphID key) override;
bool GetDrawGlyphShadow() override;
GlyphID MapCharToGlyph(WChar key) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; }
const void *GetFontTable(uint32 tag, size_t &length) override { length = 0; return nullptr; }
const char *GetFontName() override { return "sprite"; }
bool IsBuiltInFont() override { return true; }
};
/**
* Create a new sprite font cache.
* @param fs The font size to create the cache for.
*/
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(nullptr)
{
this->InitializeUnicodeGlyphMap();
this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs));
}
/**
* Free everything we allocated.
*/
SpriteFontCache::~SpriteFontCache()
{
this->ClearGlyphToSpriteMap();
}
SpriteID SpriteFontCache::GetUnicodeGlyph(WChar key)
{
if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) return 0;
return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)];
}
void SpriteFontCache::SetUnicodeGlyph(WChar key, SpriteID sprite)
{
if (this->glyph_to_spriteid_map == nullptr) this->glyph_to_spriteid_map = CallocT<SpriteID*>(256);
if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT<SpriteID>(256);
this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
}
void SpriteFontCache::InitializeUnicodeGlyphMap()
{
/* Clear out existing glyph map if it exists */
this->ClearGlyphToSpriteMap();
SpriteID base;
switch (this->fs) {
default: NOT_REACHED();
case FS_MONO: // Use normal as default for mono spaced font
case FS_NORMAL: base = SPR_ASCII_SPACE; break;
case FS_SMALL: base = SPR_ASCII_SPACE_SMALL; break;
case FS_LARGE: base = SPR_ASCII_SPACE_BIG; break;
}
for (uint i = ASCII_LETTERSTART; i < 256; i++) {
SpriteID sprite = base + i - ASCII_LETTERSTART;
if (!SpriteExists(sprite)) continue;
this->SetUnicodeGlyph(i, sprite);
this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
}
for (uint i = 0; i < lengthof(_default_unicode_map); i++) {
byte key = _default_unicode_map[i].key;
if (key == CLRA) {
/* Clear the glyph. This happens if the glyph at this code point
* is non-standard and should be accessed by an SCC_xxx enum
* entry only. */
this->SetUnicodeGlyph(_default_unicode_map[i].code, 0);
} else {
SpriteID sprite = base + key - ASCII_LETTERSTART;
this->SetUnicodeGlyph(_default_unicode_map[i].code, sprite);
}
}
font_height_cache[this->fs] = this->GetHeight();
}
/**
* Clear the glyph to sprite mapping.
*/
void SpriteFontCache::ClearGlyphToSpriteMap()
{
if (this->glyph_to_spriteid_map == nullptr) return;
for (uint i = 0; i < 256; i++) {
free(this->glyph_to_spriteid_map[i]);
}
free(this->glyph_to_spriteid_map);
this->glyph_to_spriteid_map = nullptr;
}
void SpriteFontCache::ClearFontCache()
{
Layouter::ResetFontCache(this->fs);
this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs));
}
const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
{
SpriteID sprite = this->GetUnicodeGlyph(key);
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
return GetSprite(sprite, ST_FONT);
}
uint SpriteFontCache::GetGlyphWidth(GlyphID key)
{
SpriteID sprite = this->GetUnicodeGlyph(key);
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
}
bool SpriteFontCache::GetDrawGlyphShadow()
{
return false;
}
/* static */ FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) };
int font_height_cache[FS_END];
@ -199,485 +59,27 @@ void UpdateFontHeightCache()
}
}
/**
* Create a new TrueTypeFontCache.
* @param fs The font size that is going to be cached.
* @param pixels The number of pixels this font should be high.
*/
TrueTypeFontCache::TrueTypeFontCache(FontSize fs, int pixels) : FontCache(fs), req_size(pixels), glyph_to_sprite(nullptr)
{
}
/**
* Free everything that was allocated for this font cache.
*/
TrueTypeFontCache::~TrueTypeFontCache()
{
/* Virtual functions get called statically in destructors, so make it explicit to remove any confusion. */
this->TrueTypeFontCache::ClearFontCache();
for (auto &iter : this->font_tables) {
free(iter.second.second);
}
}
/**
* Reset cached glyphs.
*/
void TrueTypeFontCache::ClearFontCache()
{
if (this->glyph_to_sprite == nullptr) return;
for (int i = 0; i < 256; i++) {
if (this->glyph_to_sprite[i] == nullptr) continue;
for (int j = 0; j < 256; j++) {
if (this->glyph_to_sprite[i][j].duplicate) continue;
free(this->glyph_to_sprite[i][j].sprite);
}
free(this->glyph_to_sprite[i]);
}
free(this->glyph_to_sprite);
this->glyph_to_sprite = nullptr;
Layouter::ResetFontCache(this->fs);
}
TrueTypeFontCache::GlyphEntry *TrueTypeFontCache::GetGlyphPtr(GlyphID key)
{
if (this->glyph_to_sprite == nullptr) return nullptr;
if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) return nullptr;
return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
}
void TrueTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate)
{
if (this->glyph_to_sprite == nullptr) {
DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs);
this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
}
if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) {
DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
}
DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
}
/* Check if a glyph should be rendered with anti-aliasing. */
static bool GetFontAAState(FontSize size, bool check_blitter = true)
bool GetFontAAState(FontSize size, bool check_blitter)
{
/* AA is only supported for 32 bpp */
if (check_blitter && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
switch (size) {
default: NOT_REACHED();
case FS_NORMAL: return _freetype.medium.aa;
case FS_SMALL: return _freetype.small.aa;
case FS_LARGE: return _freetype.large.aa;
case FS_MONO: return _freetype.mono.aa;
}
}
bool TrueTypeFontCache::GetDrawGlyphShadow()
{
return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL);
}
uint TrueTypeFontCache::GetGlyphWidth(GlyphID key)
{
if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
GlyphEntry *glyph = this->GetGlyphPtr(key);
if (glyph == nullptr || glyph->sprite == nullptr) {
this->GetGlyph(key);
glyph = this->GetGlyphPtr(key);
}
return glyph->width;
}
const Sprite *TrueTypeFontCache::GetGlyph(GlyphID key)
{
if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyph(key);
/* Check for the glyph in our cache */
GlyphEntry *glyph = this->GetGlyphPtr(key);
if (glyph != nullptr && glyph->sprite != nullptr) return glyph->sprite;
if (key == 0) {
GlyphID question_glyph = this->MapCharToGlyph('?');
if (question_glyph == 0) {
/* The font misses the '?' character. Use built-in sprite.
* Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
#define CPSET { 0, 0, 0, 0, 1 }
#define CP___ { 0, 0, 0, 0, 0 }
static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = {
CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
};
#undef CPSET
#undef CP___
static const SpriteLoader::Sprite builtin_questionmark = {
10, // height
8, // width
0, // x_offs
0, // y_offs
ST_FONT,
SCC_PAL,
builtin_questionmark_data
};
Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, SimpleSpriteAlloc);
assert(spr != nullptr);
GlyphEntry new_glyph;
new_glyph.sprite = spr;
new_glyph.width = spr->width + (this->fs != FS_NORMAL);
this->SetGlyphPtr(key, &new_glyph, false);
return new_glyph.sprite;
} else {
/* Use '?' for missing characters. */
this->GetGlyph(question_glyph);
glyph = this->GetGlyphPtr(question_glyph);
this->SetGlyphPtr(key, glyph, true);
return glyph->sprite;
}
}
return this->InternalGetGlyph(key, GetFontAAState(this->fs));
}
const void *TrueTypeFontCache::GetFontTable(uint32 tag, size_t &length)
{
const FontTable::iterator iter = this->font_tables.Find(tag);
if (iter != this->font_tables.data() + this->font_tables.size()) {
length = iter->second.first;
return iter->second.second;
}
const void *result = this->InternalGetFontTable(tag, length);
this->font_tables.Insert(tag, std::pair<size_t, const void *>(length, result));
return result;
}
#ifdef WITH_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_TRUETYPE_TABLES_H
/** Font cache for fonts that are based on a freetype font. */
class FreeTypeFontCache : public TrueTypeFontCache {
private:
FT_Face face; ///< The font face associated with this font.
void SetFontSize(FontSize fs, FT_Face face, int pixels);
virtual const void *InternalGetFontTable(uint32 tag, size_t &length);
virtual const Sprite *InternalGetGlyph(GlyphID key, bool aa);
public:
FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
~FreeTypeFontCache();
virtual void ClearFontCache();
virtual GlyphID MapCharToGlyph(WChar key);
virtual const char *GetFontName() { return face->family_name; }
virtual bool IsBuiltInFont() { return false; }
};
FT_Library _library = nullptr;
/**
* Create a new FreeTypeFontCache.
* @param fs The font size that is going to be cached.
* @param face The font that has to be loaded.
* @param pixels The number of pixels this font should be high.
*/
FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : TrueTypeFontCache(fs, pixels), face(face)
{
assert(face != nullptr);
this->SetFontSize(fs, face, pixels);
}
void FreeTypeFontCache::SetFontSize(FontSize fs, FT_Face face, int pixels)
{
if (pixels == 0) {
/* Try to determine a good height based on the minimal height recommended by the font. */
int scaled_height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs));
pixels = scaled_height;
TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
if (head != nullptr) {
/* Font height is minimum height plus the difference between the default
* height for this font size and the small size. */
int diff = scaled_height - ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL));
pixels = Clamp(std::min<uint>(head->Lowest_Rec_PPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height, MAX_FONT_SIZE);
}
} else {
pixels = ScaleFontTrad(pixels);
}
this->used_size = pixels;
FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
if (err != FT_Err_Ok) {
/* Find nearest size to that requested */
FT_Bitmap_Size *bs = this->face->available_sizes;
int i = this->face->num_fixed_sizes;
if (i > 0) { // In pathetic cases one might get no fixed sizes at all.
int n = bs->height;
FT_Int chosen = 0;
for (; --i; bs++) {
if (abs(pixels - bs->height) >= abs(pixels - n)) continue;
n = bs->height;
chosen = this->face->num_fixed_sizes - i;
}
/* Don't use FT_Set_Pixel_Sizes here - it might give us another
* error, even though the size is available (FS#5885). */
err = FT_Select_Size(this->face, chosen);
}
}
if (err == FT_Err_Ok) {
this->units_per_em = this->face->units_per_EM;
this->ascender = this->face->size->metrics.ascender >> 6;
this->descender = this->face->size->metrics.descender >> 6;
this->height = this->ascender - this->descender;
} else {
/* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
DEBUG(freetype, 0, "Font size selection failed. Using FontCache defaults.");
}
font_height_cache[this->fs] = this->GetHeight();
}
/**
* Loads the freetype font.
* First type to load the fontname as if it were a path. If that fails,
* try to resolve the filename of the font using fontconfig, where the
* format is 'font family name' or 'font family name, font style'.
* @param fs The font size to load.
*/
static void LoadFreeTypeFont(FontSize fs)
{
FreeTypeSubSetting *settings = nullptr;
switch (fs) {
default: NOT_REACHED();
case FS_SMALL: settings = &_freetype.small; break;
case FS_NORMAL: settings = &_freetype.medium; break;
case FS_LARGE: settings = &_freetype.large; break;
case FS_MONO: settings = &_freetype.mono; break;
}
if (settings->font.empty()) return;
if (_library == nullptr) {
if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
return;
}
DEBUG(freetype, 2, "Initialized");
case FS_NORMAL: return _fcsettings.medium.aa;
case FS_SMALL: return _fcsettings.small.aa;
case FS_LARGE: return _fcsettings.large.aa;
case FS_MONO: return _fcsettings.mono.aa;
}
const char *font_name = settings->font.c_str();
FT_Face face = nullptr;
/* If font is an absolute path to a ttf, try loading that first. */
FT_Error error = FT_New_Face(_library, font_name, 0, &face);
#if defined(WITH_COCOA)
extern void MacOSRegisterExternalFont(const char *file_path);
if (error == FT_Err_Ok) MacOSRegisterExternalFont(font_name);
#endif
if (error != FT_Err_Ok) {
/* Check if font is a relative filename in one of our search-paths. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
error = FT_New_Face(_library, full_font.c_str(), 0, &face);
#if defined(WITH_COCOA)
if (error == FT_Err_Ok) MacOSRegisterExternalFont(full_font.c_str());
#endif
}
}
/* Try loading based on font face name (OS-wide fonts). */
if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, &face);
if (error == FT_Err_Ok) {
DEBUG(freetype, 2, "Requested '%s', using '%s %s'", 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;
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);
static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, SIZE_TO_NAME[fs], error);
return;
found_face:
new FreeTypeFontCache(fs, face, settings->size);
}
/**
* Free everything that was allocated for this font cache.
*/
FreeTypeFontCache::~FreeTypeFontCache()
{
FT_Done_Face(this->face);
this->face = nullptr;
this->ClearFontCache();
}
/**
* Reset cached glyphs.
*/
void FreeTypeFontCache::ClearFontCache()
{
/* Font scaling might have changed, determine font size anew if it was automatically selected. */
if (this->face != nullptr) this->SetFontSize(this->fs, this->face, this->req_size);
this->TrueTypeFontCache::ClearFontCache();
}
const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa)
{
FT_GlyphSlot slot = this->face->glyph;
FT_Load_Glyph(this->face, key, aa ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
/* Despite requesting a normal glyph, FreeType may have returned a bitmap */
aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
uint width = std::max(1U, (uint)slot->bitmap.width + (this->fs == FS_NORMAL));
uint height = std::max(1U, (uint)slot->bitmap.rows + (this->fs == FS_NORMAL));
/* Limit glyph size to prevent overflows later on. */
if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) usererror("Font glyph is too large");
/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
SpriteLoader::Sprite sprite;
sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
sprite.type = ST_FONT;
sprite.colours = (aa ? SCC_PAL | SCC_ALPHA : SCC_PAL);
sprite.width = width;
sprite.height = height;
sprite.x_offs = slot->bitmap_left;
sprite.y_offs = this->ascender - slot->bitmap_top;
/* Draw shadow for medium size */
if (this->fs == FS_NORMAL && !aa) {
for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
if (HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
sprite.data[1 + x + (1 + y) * sprite.width].a = 0xFF;
}
}
}
}
for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
sprite.data[x + y * sprite.width].m = FACE_COLOUR;
sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
}
}
}
GlyphEntry new_glyph;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, SimpleSpriteAlloc);
new_glyph.width = slot->advance.x >> 6;
this->SetGlyphPtr(key, &new_glyph);
return new_glyph.sprite;
}
GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key)
{
assert(IsPrintable(key));
if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
return this->parent->MapCharToGlyph(key);
}
return FT_Get_Char_Index(this->face, key);
}
const void *FreeTypeFontCache::InternalGetFontTable(uint32 tag, size_t &length)
{
FT_ULong len = 0;
FT_Byte *result = nullptr;
FT_Load_Sfnt_Table(this->face, tag, 0, nullptr, &len);
if (len > 0) {
result = MallocT<FT_Byte>(len);
FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
}
length = len;
return result;
}
#endif /* WITH_FREETYPE */
/**
* (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
* @param monospace Whether to initialise the monospace or regular fonts.
*/
void InitFreeType(bool monospace)
void InitFontCache(bool monospace)
{
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
if (monospace != (fs == FS_MONO)) continue;
@ -686,6 +88,7 @@ void InitFreeType(bool monospace)
if (fc->HasParent()) delete fc;
#ifdef WITH_FREETYPE
extern void LoadFreeTypeFont(FontSize fs);
LoadFreeTypeFont(fs);
#elif defined(_WIN32)
extern void LoadWin32Font(FontSize fs);
@ -700,7 +103,7 @@ void InitFreeType(bool monospace)
/**
* Free everything allocated w.r.t. fonts.
*/
void UninitFreeType()
void UninitFontCache()
{
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
FontCache *fc = FontCache::Get(fs);
@ -708,8 +111,8 @@ void UninitFreeType()
}
#ifdef WITH_FREETYPE
FT_Done_FreeType(_library);
_library = nullptr;
extern void UninitFreeType();
UninitFreeType();
#endif /* WITH_FREETYPE */
}
@ -728,9 +131,5 @@ bool HasAntialiasedFonts()
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
#ifdef WITH_FREETYPE
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
#endif /* WITH_FREETYPE */
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { return false; }
bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { return false; }
#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */

@ -75,13 +75,6 @@ public:
*/
virtual int GetFontSize() const { return this->height; }
/**
* Get the SpriteID mapped to the given key
* @param key The key to get the sprite for.
* @return The sprite.
*/
virtual SpriteID GetUnicodeGlyph(WChar key) = 0;
/**
* Map a SpriteID to the key
* @param key The key to map to.
@ -170,12 +163,6 @@ public:
virtual bool IsBuiltInFont() = 0;
};
/** Get the SpriteID mapped to the given font size and key */
static inline SpriteID GetUnicodeGlyph(FontSize size, WChar key)
{
return FontCache::Get(size)->GetUnicodeGlyph(key);
}
/** Map a SpriteID to the font size and key */
static inline void SetUnicodeGlyph(FontSize size, WChar key, SpriteID sprite)
{
@ -216,8 +203,8 @@ static inline bool GetDrawGlyphShadow(FontSize size)
return FontCache::Get(size)->GetDrawGlyphShadow();
}
/** Settings for a single freetype font. */
struct FreeTypeSubSetting {
/** Settings for a single font. */
struct FontCacheSubSetting {
std::string font; ///< The name of the font, or path to the font.
uint size; ///< The (requested) size of the font.
bool aa; ///< Whether to do anti aliasing or not.
@ -225,18 +212,20 @@ struct FreeTypeSubSetting {
const void *os_handle = nullptr; ///< Optional native OS font info. Only valid during font search.
};
/** Settings for the freetype fonts. */
struct FreeTypeSettings {
FreeTypeSubSetting small; ///< The smallest font; mostly used for zoomed out view.
FreeTypeSubSetting medium; ///< The normal font size.
FreeTypeSubSetting large; ///< The largest font; mostly used for newspapers.
FreeTypeSubSetting mono; ///< The mono space font used for license/readme viewers.
/** Settings for the four different fonts. */
struct FontCacheSettings {
FontCacheSubSetting small; ///< The smallest font; mostly used for zoomed out view.
FontCacheSubSetting medium; ///< The normal font size.
FontCacheSubSetting large; ///< The largest font; mostly used for newspapers.
FontCacheSubSetting mono; ///< The mono space font used for license/readme viewers.
};
extern FreeTypeSettings _freetype;
extern FontCacheSettings _fcsettings;
void InitFreeType(bool monospace);
void UninitFreeType();
void InitFontCache(bool monospace);
void UninitFontCache();
bool HasAntialiasedFonts();
bool GetFontAAState(FontSize size, bool check_blitter = true);
#endif /* FONTCACHE_H */

@ -0,0 +1,11 @@
add_files(
freetypefontcache.cpp
CONDITION Freetype_FOUND
)
add_files(
spritefontcache.cpp
spritefontcache.h
truetypefontcache.cpp
truetypefontcache.h
)

@ -0,0 +1,332 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file freetypefontcache.cpp FreeType font cache implementation. */
#include "../stdafx.h"
#include "../debug.h"
#include "../fontcache.h"
#include "../fontdetection.h"
#include "../blitter/factory.hpp"
#include "../core/math_func.hpp"
#include "../zoom_func.h"
#include "../fileio_func.h"
#include "truetypefontcache.h"
#include "../table/control_codes.h"
#include "../safeguards.h"
#ifdef WITH_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_TRUETYPE_TABLES_H
/** Font cache for fonts that are based on a freetype font. */
class FreeTypeFontCache : public TrueTypeFontCache {
private:
FT_Face face; ///< The font face associated with this font.
void SetFontSize(FontSize fs, FT_Face face, int pixels);
virtual const void *InternalGetFontTable(uint32 tag, size_t &length);
virtual const Sprite *InternalGetGlyph(GlyphID key, bool aa);
public:
FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
~FreeTypeFontCache();
virtual void ClearFontCache();
virtual GlyphID MapCharToGlyph(WChar key);
virtual const char *GetFontName() { return face->family_name; }
virtual bool IsBuiltInFont() { return false; }
};
FT_Library _library = nullptr;
/**
* Create a new FreeTypeFontCache.
* @param fs The font size that is going to be cached.
* @param face The font that has to be loaded.
* @param pixels The number of pixels this font should be high.
*/
FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : TrueTypeFontCache(fs, pixels), face(face)
{
assert(face != nullptr);
this->SetFontSize(fs, face, pixels);
}
void FreeTypeFontCache::SetFontSize(FontSize fs, FT_Face face, int pixels)
{
if (pixels == 0) {
/* Try to determine a good height based on the minimal height recommended by the font. */
int scaled_height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs));
pixels = scaled_height;
TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
if (head != nullptr) {
/* Font height is minimum height plus the difference between the default
* height for this font size and the small size. */
int diff = scaled_height - ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL));
pixels = Clamp(std::min<uint>(head->Lowest_Rec_PPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height, MAX_FONT_SIZE);
}
} else {
pixels = ScaleFontTrad(pixels);
}
this->used_size = pixels;
FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
if (err != FT_Err_Ok) {
/* Find nearest size to that requested */
FT_Bitmap_Size *bs = this->face->available_sizes;
int i = this->face->num_fixed_sizes;
if (i > 0) { // In pathetic cases one might get no fixed sizes at all.
int n = bs->height;
FT_Int chosen = 0;
for (; --i; bs++) {
if (abs(pixels - bs->height) >= abs(pixels - n)) continue;
n = bs->height;
chosen = this->face->num_fixed_sizes - i;
}
/* Don't use FT_Set_Pixel_Sizes here - it might give us another
* error, even though the size is available (FS#5885). */
err = FT_Select_Size(this->face, chosen);
}
}
if (err == FT_Err_Ok) {
this->units_per_em = this->face->units_per_EM;
this->ascender = this->face->size->metrics.ascender >> 6;
this->descender = this->face->size->metrics.descender >> 6;
this->height = this->ascender - this->descender;
} else {
/* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
DEBUG(fontcache, 0, "Font size selection failed. Using FontCache defaults.");
}
font_height_cache[this->fs] = this->GetHeight();
}
/**
* Loads the freetype font.
* First type to load the fontname as if it were a path. If that fails,
* try to resolve the filename of the font using fontconfig, where the
* format is 'font family name' or 'font family name, font style'.
* @param fs The font size to load.
*/
void LoadFreeTypeFont(FontSize fs)
{
FontCacheSubSetting *settings = nullptr;
switch (fs) {
default: NOT_REACHED();
case FS_SMALL: settings = &_fcsettings.small; break;
case FS_NORMAL: settings = &_fcsettings.medium; break;
case FS_LARGE: settings = &_fcsettings.large; break;
case FS_MONO: settings = &_fcsettings.mono; break;
}
if (settings->font.empty()) return;
if (_library == nullptr) {
if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
return;
}
DEBUG(fontcache, 2, "Initialized");
}
const char *font_name = settings->font.c_str();
FT_Face face = nullptr;
/* If font is an absolute path to a ttf, try loading that first. */
FT_Error error = FT_New_Face(_library, font_name, 0, &face);
#if defined(WITH_COCOA)
extern void MacOSRegisterExternalFont(const char *file_path);
if (error == FT_Err_Ok) MacOSRegisterExternalFont(font_name);
#endif
if (error != FT_Err_Ok) {
/* Check if font is a relative filename in one of our search-paths. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
error = FT_New_Face(_library, full_font.c_str(), 0, &face);
#if defined(WITH_COCOA)
if (error == FT_Err_Ok) MacOSRegisterExternalFont(full_font.c_str());
#endif
}
}
/* Try loading based on font face name (OS-wide fonts). */
if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, &face);
if (error == FT_Err_Ok) {
DEBUG(fontcache, 2, "Requested '%s', using '%s %s'", 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;
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);
static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, SIZE_TO_NAME[fs], error);
return;
found_face:
new FreeTypeFontCache(fs, face, settings->size);
}
/**
* Free everything that was allocated for this font cache.
*/
FreeTypeFontCache::~FreeTypeFontCache()
{
FT_Done_Face(this->face);
this->face = nullptr;
this->ClearFontCache();
}
/**
* Reset cached glyphs.
*/
void FreeTypeFontCache::ClearFontCache()
{
/* Font scaling might have changed, determine font size anew if it was automatically selected. */
if (this->face != nullptr) this->SetFontSize(this->fs, this->face, this->req_size);
this->TrueTypeFontCache::ClearFontCache();
}
const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa)
{
FT_GlyphSlot slot = this->face->glyph;
FT_Load_Glyph(this->face, key, aa ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
/* Despite requesting a normal glyph, FreeType may have returned a bitmap */
aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
uint width = std::max(1U, (uint)slot->bitmap.width + (this->fs == FS_NORMAL));
uint height = std::max(1U, (uint)slot->bitmap.rows + (this->fs == FS_NORMAL));
/* Limit glyph size to prevent overflows later on. */
if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) usererror("Font glyph is too large");
/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
SpriteLoader::Sprite sprite;
sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
sprite.type = ST_FONT;
sprite.colours = (aa ? SCC_PAL | SCC_ALPHA : SCC_PAL);
sprite.width = width;
sprite.height = height;
sprite.x_offs = slot->bitmap_left;
sprite.y_offs = this->ascender - slot->bitmap_top;
/* Draw shadow for medium size */
if (this->fs == FS_NORMAL && !aa) {
for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
if (HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
sprite.data[1 + x + (1 + y) * sprite.width].a = 0xFF;
}
}
}
}
for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
sprite.data[x + y * sprite.width].m = FACE_COLOUR;
sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
}
}
}
GlyphEntry new_glyph;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, SimpleSpriteAlloc);
new_glyph.width = slot->advance.x >> 6;
this->SetGlyphPtr(key, &new_glyph);
return new_glyph.sprite;
}
GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key)
{
assert(IsPrintable(key));
if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
return this->parent->MapCharToGlyph(key);
}
return FT_Get_Char_Index(this->face, key);
}
const void *FreeTypeFontCache::InternalGetFontTable(uint32 tag, size_t &length)
{
FT_ULong len = 0;
FT_Byte *result = nullptr;
FT_Load_Sfnt_Table(this->face, tag, 0, nullptr, &len);
if (len > 0) {
result = MallocT<FT_Byte>(len);
FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
}
length = len;
return result;
}
/**
* Free everything allocated w.r.t. freetype.
*/
void UninitFreeType()
{
FT_Done_FreeType(_library);
_library = nullptr;
}
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */
#endif /* WITH_FREETYPE */

@ -0,0 +1,128 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file spritefontcache.cpp Sprite fontcache implementation. */
#include "../stdafx.h"
#include "../fontcache.h"
#include "../gfx_layout.h"
#include "../zoom_func.h"
#include "spritefontcache.h"
#include "../table/sprites.h"
#include "../table/control_codes.h"
#include "../table/unicode.h"
#include "../safeguards.h"
static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter.
/**
* Create a new sprite font cache.
* @param fs The font size to create the cache for.
*/
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(nullptr)
{
this->InitializeUnicodeGlyphMap();
this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs));
}
/**
* Free everything we allocated.
*/
SpriteFontCache::~SpriteFontCache()
{
this->ClearGlyphToSpriteMap();
}
SpriteID SpriteFontCache::GetUnicodeGlyph(WChar key)
{
if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) return 0;
return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)];
}
void SpriteFontCache::SetUnicodeGlyph(WChar key, SpriteID sprite)
{
if (this->glyph_to_spriteid_map == nullptr) this->glyph_to_spriteid_map = CallocT<SpriteID*>(256);
if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT<SpriteID>(256);
this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
}
void SpriteFontCache::InitializeUnicodeGlyphMap()
{
/* Clear out existing glyph map if it exists */
this->ClearGlyphToSpriteMap();
SpriteID base;
switch (this->fs) {
default: NOT_REACHED();
case FS_MONO: // Use normal as default for mono spaced font
case FS_NORMAL: base = SPR_ASCII_SPACE; break;
case FS_SMALL: base = SPR_ASCII_SPACE_SMALL; break;
case FS_LARGE: base = SPR_ASCII_SPACE_BIG; break;
}
for (uint i = ASCII_LETTERSTART; i < 256; i++) {
SpriteID sprite = base + i - ASCII_LETTERSTART;
if (!SpriteExists(sprite)) continue;
this->SetUnicodeGlyph(i, sprite);
this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
}
for (uint i = 0; i < lengthof(_default_unicode_map); i++) {
byte key = _default_unicode_map[i].key;
if (key == CLRA) {
/* Clear the glyph. This happens if the glyph at this code point
* is non-standard and should be accessed by an SCC_xxx enum
* entry only. */
this->SetUnicodeGlyph(_default_unicode_map[i].code, 0);
} else {
SpriteID sprite = base + key - ASCII_LETTERSTART;
this->SetUnicodeGlyph(_default_unicode_map[i].code, sprite);
}
}
font_height_cache[this->fs] = this->GetHeight();
}
/**
* Clear the glyph to sprite mapping.
*/
void SpriteFontCache::ClearGlyphToSpriteMap()
{
if (this->glyph_to_spriteid_map == nullptr) return;
for (uint i = 0; i < 256; i++) {
free(this->glyph_to_spriteid_map[i]);
}
free(this->glyph_to_spriteid_map);
this->glyph_to_spriteid_map = nullptr;
}
void SpriteFontCache::ClearFontCache()
{
Layouter::ResetFontCache(this->fs);
this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs));
}
const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
{
SpriteID sprite = this->GetUnicodeGlyph(key);
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
return GetSprite(sprite, ST_FONT);
}
uint SpriteFontCache::GetGlyphWidth(GlyphID key)
{
SpriteID sprite = this->GetUnicodeGlyph(key);
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
}
bool SpriteFontCache::GetDrawGlyphShadow()
{
return false;
}

@ -0,0 +1,38 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file spritefontcache.h Sprite font cache implementation definition. */
#ifndef SPRITEFONTCACHE_H
#define SPRITEFONTCACHE_H
#include "../string_func.h"
#include "../fontcache.h"
/** Font cache for fonts that are based on a freetype font. */
class SpriteFontCache : public FontCache {
private:
SpriteID **glyph_to_spriteid_map; ///< Mapping of glyphs to sprite IDs.
SpriteID GetUnicodeGlyph(WChar key);
void ClearGlyphToSpriteMap();
public:
SpriteFontCache(FontSize fs);
~SpriteFontCache();
virtual void SetUnicodeGlyph(WChar key, SpriteID sprite);
virtual void InitializeUnicodeGlyphMap();
virtual void ClearFontCache();
virtual const Sprite *GetGlyph(GlyphID key);
virtual uint GetGlyphWidth(GlyphID key);
virtual bool GetDrawGlyphShadow();
virtual GlyphID MapCharToGlyph(WChar key) { assert(IsPrintable(key)); return SPRITE_GLYPH | key; }
virtual const void *GetFontTable(uint32 tag, size_t &length) { length = 0; return nullptr; }
virtual const char *GetFontName() { return "sprite"; }
virtual bool IsBuiltInFont() { return true; }
};
#endif /* SPRITEFONTCACHE_H */

@ -0,0 +1,180 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file truetypefontcache.cpp Common base implementation for font file based font caches. */
#include "../stdafx.h"
#include "../debug.h"
#include "../fontcache.h"
#include "../blitter/factory.hpp"
#include "../core/bitmath_func.hpp"
#include "../gfx_layout.h"
#include "truetypefontcache.h"
#include "../safeguards.h"
/**
* Create a new TrueTypeFontCache.
* @param fs The font size that is going to be cached.
* @param pixels The number of pixels this font should be high.
*/
TrueTypeFontCache::TrueTypeFontCache(FontSize fs, int pixels) : FontCache(fs), req_size(pixels), glyph_to_sprite(nullptr)
{
}
/**
* Free everything that was allocated for this font cache.
*/
TrueTypeFontCache::~TrueTypeFontCache()
{
/* Virtual functions get called statically in destructors, so make it explicit to remove any confusion. */
this->TrueTypeFontCache::ClearFontCache();
for (auto &iter : this->font_tables) {
free(iter.second.second);
}
}
/**
* Reset cached glyphs.
*/
void TrueTypeFontCache::ClearFontCache()
{
if (this->glyph_to_sprite == nullptr) return;
for (int i = 0; i < 256; i++) {
if (this->glyph_to_sprite[i] == nullptr) continue;
for (int j = 0; j < 256; j++) {
if (this->glyph_to_sprite[i][j].duplicate) continue;
free(this->glyph_to_sprite[i][j].sprite);
}
free(this->glyph_to_sprite[i]);
}
free(this->glyph_to_sprite);
this->glyph_to_sprite = nullptr;
Layouter::ResetFontCache(this->fs);
}
TrueTypeFontCache::GlyphEntry *TrueTypeFontCache::GetGlyphPtr(GlyphID key)
{
if (this->glyph_to_sprite == nullptr) return nullptr;
if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) return nullptr;
return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
}
void TrueTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate)
{
if (this->glyph_to_sprite == nullptr) {
DEBUG(fontcache, 3, "Allocating root glyph cache for size %u", this->fs);
this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
}
if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) {
DEBUG(fontcache, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
}
DEBUG(fontcache, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
}
bool TrueTypeFontCache::GetDrawGlyphShadow()
{
return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL);
}
uint TrueTypeFontCache::GetGlyphWidth(GlyphID key)
{
if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
GlyphEntry *glyph = this->GetGlyphPtr(key);
if (glyph == nullptr || glyph->sprite == nullptr) {
this->GetGlyph(key);
glyph = this->GetGlyphPtr(key);
}
return glyph->width;
}
const Sprite *TrueTypeFontCache::GetGlyph(GlyphID key)
{
if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyph(key);
/* Check for the glyph in our cache */
GlyphEntry *glyph = this->GetGlyphPtr(key);
if (glyph != nullptr && glyph->sprite != nullptr) return glyph->sprite;
if (key == 0) {
GlyphID question_glyph = this->MapCharToGlyph('?');
if (question_glyph == 0) {
/* The font misses the '?' character. Use built-in sprite.
* Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
#define CPSET { 0, 0, 0, 0, 1 }
#define CP___ { 0, 0, 0, 0, 0 }
static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = {
CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
};
#undef CPSET
#undef CP___
static const SpriteLoader::Sprite builtin_questionmark = {
10, // height
8, // width
0, // x_offs
0, // y_offs
ST_FONT,
SCC_PAL,
builtin_questionmark_data
};
Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, SimpleSpriteAlloc);
assert(spr != nullptr);
GlyphEntry new_glyph;
new_glyph.sprite = spr;
new_glyph.width = spr->width + (this->fs != FS_NORMAL);
this->SetGlyphPtr(key, &new_glyph, false);
return new_glyph.sprite;
} else {
/* Use '?' for missing characters. */
this->GetGlyph(question_glyph);
glyph = this->GetGlyphPtr(question_glyph);
this->SetGlyphPtr(key, glyph, true);
return glyph->sprite;
}
}
return this->InternalGetGlyph(key, GetFontAAState(this->fs));
}
const void *TrueTypeFontCache::GetFontTable(uint32 tag, size_t &length)
{
const FontTable::iterator iter = this->font_tables.Find(tag);
if (iter != this->font_tables.data() + this->font_tables.size()) {
length = iter->second.first;
return iter->second.second;
}
const void *result = this->InternalGetFontTable(tag, length);
this->font_tables.Insert(tag, std::pair<size_t, const void *>(length, result));
return result;
}

@ -5,13 +5,13 @@
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file fontcache_internal.h Support types and functions for platform-specific font support. */
/** @file truetypefontcache.h Common base definition for font file based font caches. */
#ifndef FONTCACHE_INTERNAL_H
#define FONTCACHE_INTERNAL_H
#ifndef TRUETYPEFONTCACHE_H
#define TRUETYPEFONTCACHE_H
#include "core/smallmap_type.hpp"
#include "fontcache.h"
#include "../core/smallmap_type.hpp"
#include "../fontcache.h"
static const int MAX_FONT_SIZE = 72; ///< Maximum font size.
@ -63,7 +63,6 @@ public:
TrueTypeFontCache(FontSize fs, int pixels);
virtual ~TrueTypeFontCache();
int GetFontSize() const override { return this->used_size; }
SpriteID GetUnicodeGlyph(WChar key) override { return this->parent->GetUnicodeGlyph(key); }
void SetUnicodeGlyph(WChar key, SpriteID sprite) override { this->parent->SetUnicodeGlyph(key, sprite); }
virtual void InitializeUnicodeGlyphMap() override
@ -81,4 +80,4 @@ public:
bool IsBuiltInFont() override { return false; }
};
#endif /* FONTCACHE_INTERNAL_H */
#endif /* TRUETYPEFONTCACHE_H */

@ -37,6 +37,6 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face);
* @param callback The function to call to check for missing glyphs.
* @return true if a font has been set, false otherwise.
*/
bool SetFallbackFont(struct FreeTypeSettings *settings, const char *language_isocode, int winlangid, class MissingGlyphSearcher *callback);
bool SetFallbackFont(struct FontCacheSettings *settings, const char *language_isocode, int winlangid, class MissingGlyphSearcher *callback);
#endif

@ -3658,6 +3658,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Interesso
STR_FINANCES_SECTION_OTHER :{GOLD}Altres
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Benefici net
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Balanç bancari

@ -1863,7 +1863,7 @@ STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3-raster
STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Willekeurig
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Steden mogen wegen bouwen: {STRING}
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Steden toestaan om wegen te bouwen ten behoeve van groei. Schakel deze optie uit als je niet wilt dat gemeenten zelf wegen bouwen.
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Steden toestaan om wegen te bouwen ten behoeve van groei. Schakel deze optie uit als je niet wilt dat steden zelf wegen bouwen.
STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Steden mogen gelijkvloerse kruisingen bouwen: {STRING}
STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Door deze optie in te schakelen, kunnen steden gelijkvloerse kruisingen bouwen.
@ -1934,8 +1934,8 @@ STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normaal
STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Snel
STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Heel snel
STR_CONFIG_SETTING_LARGER_TOWNS :Verhouding van gemeenten die uitgroeien tot steden: {STRING}
STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Aantal steden die een stad worden, dus een stad die groter begint en sneller groeit
STR_CONFIG_SETTING_LARGER_TOWNS :Verhouding van dorpen die uitgroeien tot steden: {STRING}
STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Aantal dorpen dat een stad wordt, dus die groter begint en sneller groeit
STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 op {COMMA}
###setting-zero-is-special
STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Geen
@ -2551,7 +2551,7 @@ STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Totale
STR_CONTENT_DETAIL_TITLE :{SILVER}INFO OVER INHOUD
###length 5
STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Je hebt ervoor gekozen om dit niet te downloaden
STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Je hebt er niet voor gekozen om dit te downloaden
STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Je hebt ervoor gekozen om dit te downloaden
STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Deze afhankelijkheid is geselecteerd om te downloaden
STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Dit heb je al
@ -3657,6 +3657,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD} Rente va
STR_FINANCES_SECTION_OTHER :{GOLD}Overig
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Nettowinst
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Banksaldo
@ -4742,17 +4743,17 @@ STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Kan geen
STR_ERROR_PROTECTED :{WHITE}Dit bedrijf verhandelt nog geen aandelen...
# Town related errors
STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Kan geen plaatsen bouwen
STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Kan plaats niet hernoemen...
STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Kan hier geen nieuwe plaats bouwen...
STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Kan geen steden bouwen
STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Kan stad niet hernoemen...
STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Kan hier geen nieuwe stad bouwen...
STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Kan dorp niet uitbreiden...
STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... te dicht bij de rand van de kaart
STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... te dicht bij een andere plaats
STR_ERROR_TOO_MANY_TOWNS :{WHITE}... te veel plaatsen
STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... er is geen ruimte meer op de kaart
STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}De plaats bouwt geen wegen. Het bouwen van wegen kan aangezet worden via Geavanceerde Instellingen->Omgeving->Plaatsen
STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}De stad bouwt geen wegen. Het bouwen van wegen kan aangezet worden via Instellingen->Omgeving->Steden
STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Wegwerkzaamheden in uitvoering
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Kan deze plaats niet verwijderen...{}Een station of depot verwijst naar deze plaats of een door de plaats beheerde tegel kan niet worden verwijderd
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Kan deze stad niet verwijderen...{}Een station of depot verwijst naar deze plaats of een door de stad beheerde tegel kan niet worden verwijderd
STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... er is geen geschikte plaats voor een standbeeld in het centrum van dit dorp
# Industry related errors
@ -4762,11 +4763,11 @@ STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Kan {STR
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Kan dit type industrie hier niet bouwen...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... te dicht bij een andere industrie
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... moet eerst dorp bouwen
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... slechts één per plaats toegestaan
STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... kan alleen in plaatsen met meer dan 1.200 inwoners worden gebouwd
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... slechts één per stad toegestaan
STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... kan alleen in steden met meer dan 1.200 inwoners worden gebouwd
STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... kan alleen in regenwouden gebouwd worden
STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... kan alleen in woestijnen gebouwd worden
STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... kan alleen in plaatsen gebouwd worden (vervangt huizen)
STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... kan alleen in steden gebouwd worden (vervangt huizen)
STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... kan alleen worden gebouwd in het centrum van de stad
STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... kan alleen in laaggelegen gebieden gebouwd worden
STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... kan alleen aan de rand van de kaart geplaatst worden
@ -4774,8 +4775,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... boss
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... kan alleen boven de sneeuwlijn gebouwd worden
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... kan alleen onder de sneeuwlijn gebouwd worden
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Er waren een geschikte locaties voor '{STRING}' industrieën
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Parameters voor kaartontwikkeling wijzigen om een betere kaart te krijgen
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Er waren geen geschikte locaties voor {STRING}-industrieën
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Wijzig de instellingen van wereldontwikkeling om een betere kaart te krijgen
# Station construction related errors
STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Kan hier geen treinstation bouwen...

@ -3683,6 +3683,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Loan Inte
STR_FINANCES_SECTION_OTHER :{GOLD}Other
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Net Profit
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bank Balance

@ -231,9 +231,9 @@ STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m
STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Auswahl-Text:
STR_LIST_FILTER_OSKTITLE :{BLACK}Filter eingeben
STR_LIST_FILTER_TOOLTIP :{BLACK}Stichwort eingeben, mit dem die Liste gefiltert werden soll
STR_LIST_FILTER_TITLE :{BLACK}Filter:
STR_LIST_FILTER_OSKTITLE :{BLACK}Einen oder mehrere Schlüsselwörter für den Listenfilter eingeben
STR_LIST_FILTER_TOOLTIP :{BLACK}Ein oder mehrere Stichwörter eingeben, mit dem die Liste gefiltert werden soll
STR_TOOLTIP_GROUP_ORDER :{BLACK}Gruppierung wählen
STR_TOOLTIP_SORT_ORDER :{BLACK}Sortierreihenfolge auswählen (absteigend/aufsteigend)
@ -1213,7 +1213,7 @@ STR_WARNING_NO_SUITABLE_AI :{WHITE}Keine KI
# Settings tree window
STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Einstellungen
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Suchtext:
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter:
STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Alles ausklappen
STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Alles einklappen
STR_CONFIG_SETTING_RESET_ALL :{BLACK}Alle Werte zurücksetzen
@ -4067,7 +4067,7 @@ STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Spielsta
STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Keine Informationen verfügbar
STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING}
STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING}
STR_SAVELOAD_FILTER_TITLE :{BLACK}Suchtext:
STR_SAVELOAD_FILTER_TITLE :{BLACK}Filter:
STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}Datei überschreiben
STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}Existierende Datei wirklich überschreiben?
STR_SAVELOAD_DIRECTORY :{STRING} (Verzeichnis)
@ -4724,6 +4724,7 @@ STR_FINANCES_SECTION_OTHER :{GOLD}Sonstiges
STR_FINANCES_SECTION_INFRASTRUCTURE_COSTS :{GOLD}Kosten für Infrastruktur-Sharing
STR_FINANCES_SECTION_INFRASTRUCTURE_INCOME :{GOLD}Einnahmen aus Infrastruktur-Sharing
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Reingewinn
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Kontostand

@ -233,8 +233,8 @@ STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtro:
STR_LIST_FILTER_OSKTITLE :{BLACK}Inserire il filtro
STR_LIST_FILTER_TOOLTIP :{BLACK}Inserire una parola da utilizzare per filtrare la lista
STR_LIST_FILTER_OSKTITLE :{BLACK}Immettere una o più parole chiave per filtrare dall'elenco
STR_LIST_FILTER_TOOLTIP :{BLACK}Immettere una o più parole chiave per filtrare dall'elenco
STR_TOOLTIP_GROUP_ORDER :{BLACK}Seleziona il criterio di raggruppamento
STR_TOOLTIP_SORT_ORDER :{BLACK}Seleziona l'ordinamento (decrescente/crescente)
@ -3694,10 +3694,11 @@ STR_FINANCES_SECTION_TRAIN_REVENUE :{GOLD}Treni
STR_FINANCES_SECTION_ROAD_VEHICLE_REVENUE :{GOLD}Automezzi
STR_FINANCES_SECTION_AIRCRAFT_REVENUE :{GOLD}Aeromobili
STR_FINANCES_SECTION_SHIP_REVENUE :{GOLD}Navi
STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Interessi sul prestito
STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Int. sul prestito
STR_FINANCES_SECTION_OTHER :{GOLD}Altro
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Profitto netto
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Saldo bancario
@ -3920,7 +3921,7 @@ STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capacit
STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Vagoni motorizzati: {GOLD}+{POWER}{BLACK} Peso: {GOLD}+{WEIGHT_SHORT}
STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Riadattabile per: {GOLD}{STRING}
STR_PURCHASE_INFO_ALL_TYPES :Tutti i tipi di carico
STR_PURCHASE_INFO_NONE :Niente
STR_PURCHASE_INFO_NONE :Nessun carico
STR_PURCHASE_INFO_ENGINES_ONLY :Solo locomotive
STR_PURCHASE_INFO_ALL_BUT :Tutto tranne {CARGO_LIST}
STR_PURCHASE_INFO_MAX_TE :{BLACK}Sforzo di trazione massimo: {GOLD}{FORCE}

@ -231,9 +231,9 @@ STR_UNITS_HEIGHT_METRIC :{COMMA}m
STR_UNITS_HEIGHT_SI :{COMMA}m
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}검색할 문자열:
STR_LIST_FILTER_OSKTITLE :{BLACK}검색할 문자를 입력하세요
STR_LIST_FILTER_TOOLTIP :{BLACK}검색할 키워드를 입력하세요
STR_LIST_FILTER_TITLE :{BLACK}검색:
STR_LIST_FILTER_OSKTITLE :{BLACK}검색할 단어를 하나 이상 입력하세요
STR_LIST_FILTER_TOOLTIP :{BLACK}검색할 단어를 하나 이상 입력하세요
STR_TOOLTIP_GROUP_ORDER :{BLACK}그룹화 순서를 선택하세요.
STR_TOOLTIP_SORT_ORDER :{BLACK}정렬 방법을 선택하세요 (내림차순/오름차순)
@ -1214,7 +1214,7 @@ STR_WARNING_NO_SUITABLE_AI :{WHITE}사용
# Settings tree window
STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}설정
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}검색할 문자열:
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}검색:
STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}모두 펼치기
STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}모두 접기
STR_CONFIG_SETTING_RESET_ALL :{BLACK}모든 설정 초기화
@ -4070,7 +4070,7 @@ STR_SAVELOAD_DETAIL_CAPTION :{BLACK}게임
STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}사용 가능한 정보 없음
STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING}
STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING}
STR_SAVELOAD_FILTER_TITLE :{BLACK}검색할 문자열:
STR_SAVELOAD_FILTER_TITLE :{BLACK}검색:
STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}파일 덮어쓰기
STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}정말로 이미 존재하는 파일에 덮어씌우시겠습니까?
STR_SAVELOAD_DIRECTORY :{STRING} (폴더)
@ -4176,7 +4176,7 @@ STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}NewGRF
STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}적용한 NewGRF 파일
STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}적용하지 않은 NewGRF 파일
STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}프리셋 선택:
STR_NEWGRF_FILTER_TITLE :{ORANGE}검색할 문자열:
STR_NEWGRF_FILTER_TITLE :{ORANGE}검색:
STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}선택한 프리셋을 불러옵니다
STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}프리셋 저장
STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}현재 목록을 프리셋으로 저장합니다
@ -4731,6 +4731,7 @@ STR_FINANCES_SECTION_INFRASTRUCTURE_COSTS :{GOLD}타사
STR_FINANCES_SECTION_INFRASTRUCTURE_INCOME :{GOLD}시설 공유 수익
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}순이익
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}현 보유 금액

@ -232,7 +232,7 @@ STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m
STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtra virkne:
STR_LIST_FILTER_TITLE :{BLACK}Filters:
STR_LIST_FILTER_OSKTITLE :{BLACK}Ievadīt filtra virkni
STR_LIST_FILTER_TOOLTIP :{BLACK}Ievadīt atslēgvārdu, lai filtrētu sarakstu

@ -4037,6 +4037,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Odsetki o
STR_FINANCES_SECTION_OTHER :{GOLD}Inne
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Zysk netto
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bilans bankowy

@ -3658,6 +3658,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Juros do
STR_FINANCES_SECTION_OTHER :{GOLD}Outros
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Lucro Líquido
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Balanço bancário

@ -3839,6 +3839,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Плат
STR_FINANCES_SECTION_OTHER :{GOLD}Прочие расходы
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Чистая прибыль
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Баланс:

@ -3657,6 +3657,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}贷款利
STR_FINANCES_SECTION_OTHER :{GOLD}其他费用
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}净利润
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}流动资金

@ -3658,6 +3658,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}T. de int
STR_FINANCES_SECTION_OTHER :{GOLD}Otros
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Utilidad neta
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Saldo en banco

@ -230,9 +230,9 @@ STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m
STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Lọc chuỗi:
STR_LIST_FILTER_OSKTITLE :{BLACK}Nhập chuỗi lọc
STR_LIST_FILTER_TOOLTIP :{BLACK}Nhập từ khóa vào để lọc danh sách
STR_LIST_FILTER_TITLE :{BLACK}Lọc:
STR_LIST_FILTER_OSKTITLE :{BLACK}Nhập một hoặc nhiều từ khóa để lọc danh sách
STR_LIST_FILTER_TOOLTIP :{BLACK}Nhập một hoặc nhiều từ khóa để lọc danh sách
STR_TOOLTIP_GROUP_ORDER :{BLACK}Chọn cách gom nhóm
STR_TOOLTIP_SORT_ORDER :{BLACK}Chọn thứ tự sắp xếp (giảm dần/tăng dần)
@ -1175,7 +1175,7 @@ STR_WARNING_NO_SUITABLE_AI :{WHITE}Không c
# Settings tree window
STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Thiết lập
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Lọc chuỗi:
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Lọc:
STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Mở xuống tất cả
STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Đóng lại tất cả
STR_CONFIG_SETTING_RESET_ALL :{BLACK}Thiết lập lại tất cả
@ -3136,7 +3136,7 @@ STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Chi Ti
STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Không có thông tin gì cả.
STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING}
STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING}
STR_SAVELOAD_FILTER_TITLE :{BLACK}Chuỗi lọc:
STR_SAVELOAD_FILTER_TITLE :{BLACK}Lọc:
STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}Ghi đè file
STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}Bạn có chắc chắn ghi đè lên file đang tồn tại?
STR_SAVELOAD_DIRECTORY :{STRING} (Thư mục)
@ -3232,7 +3232,7 @@ STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Thông t
STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Các NewGRP đã kích hoạt
STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Các NewGRF chưa kích hoạt
STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Chọn bộ tham số:
STR_NEWGRF_FILTER_TITLE :{ORANGE}Lọc giá trị:
STR_NEWGRF_FILTER_TITLE :{ORANGE}Lọc:
STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Nạp các thiết lập đã chọn
STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Lưu thiết lập
STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Lưu danh sách này như là thiết lập
@ -3657,6 +3657,7 @@ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Lãi vay
STR_FINANCES_SECTION_OTHER :{GOLD}Khác
STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG}
STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG}
STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG}
STR_FINANCES_NET_PROFIT :{WHITE}Lợi Nhuận Ròng
STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Số dư hiện có

@ -170,6 +170,7 @@ STR_LITERS :{COMMA}{NBSP}li
STR_ITEMS :{COMMA}{NBSP}eitem
STR_CRATES :{COMMA}{NBSP}crât
STR_COLOUR_DEFAULT :Rhagosodiad
###length 17
STR_COLOUR_DARK_BLUE :Glas Tywyll
STR_COLOUR_PALE_GREEN :Gwyrdd Golau
@ -1334,6 +1335,7 @@ STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Nid yw'n
STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Cynnal a chadw tanadeiledd: {STRING}
STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Pan fo wedi'i alluogi, mae tanadeiledd yn creu costau cynnal a chadw. Mae'r cost yn codi'n gyflymach na'i gyfradd gyda thŵf y rhwydwaith, gan effeithio'n fwy ar gwmniau mawr na rhai bychan
STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_HELPTEXT :Dewiswch liw dechreuol am y cwmni
STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Maes awyr ddim yn dibennu: {STRING}
STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Mae galluogi'r dewis yma'n peri i bob math o faes awyr aros ar gael am byth wedi ei gyflwyniad gyntaf
@ -1932,6 +1934,7 @@ STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Allan o
STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Methwyd dyroddi {BYTES} o storfa corluniau. Lleihawyd y storfa corluniau at {BYTES}. Bydd hyn yn lleihau perfformiad OpenTTD. I leihau gofynion cof gallwch roi cynnig ar analluogi graffigiau 32 did a/neu lefelau mwyháu
# Video initalization errors
STR_VIDEO_DRIVER_ERROR :{WHITE}Gwall gyda'r gosodiadau fideo...
# Intro window
STR_INTRO_CAPTION :{WHITE}OpenTTD {REV}
@ -2194,6 +2197,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Rhestr Cleienti
STR_NETWORK_COMPANY_LIST_SPECTATE :Gwylio
# Network client list
STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Anfon neges i bob gwyliwr
# Matches ConnectionType
###length 5
@ -2809,6 +2813,7 @@ STR_ABOUT_VERSION :{BLACK}fersiwn
STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-{STRING} Y tîm OpenTTD
# Framerate display window
STR_FRAMERATE_CAPTION_SMALL :{STRING}{WHITE} ({DECIMAL}x)
STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP :{BLACK}Nifer y ticiau gêm a efelychir bob eiliad.
STR_FRAMERATE_RATE_BLITTER_TOOLTIP :{BLACK}Nifer o fframiau fideo a lunir bob eiliad.
STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}Pa mor gyflym mae'r gêm yn rhedeg, o gymharu a'r cyflymder i'w ddisgwyl ar gyfradd efelychu arferol.
@ -2817,6 +2822,7 @@ STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMA
###length 15
STR_FRAMERATE_GL_ECONOMY :{BLACK} Trin cargo:
STR_FRAMERATE_VIDEO :{BLACK}Allbwn fideo:
###length 15
STR_FRAMETIME_CAPTION_VIDEO :Allbwn fideo
@ -4014,6 +4020,7 @@ STR_ORDER_REFIT_STOP_ORDER :(Ailfitio i {ST
STR_ORDER_STOP_ORDER :(Stopio)
STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING}
STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Methu defnyddio gorsaf){POP_COLOUR} {STRING} {STATION} {STRING}
STR_ORDER_IMPLICIT :(Ymhlyg)

@ -401,6 +401,8 @@ CommandCost CmdBuildObject(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
case OBJECT_HQ: {
Company *c = Company::Get(_current_company);
if (c->location_of_HQ != INVALID_TILE) {
/* Don't relocate HQ on the same location. */
if (c->location_of_HQ == tile) return_cmd_error(STR_ERROR_ALREADY_BUILT);
/* We need to persuade a bit harder to remove the old HQ. */
_current_company = OWNER_WATER;
cost.AddCost(ClearTile_Object(c->location_of_HQ, flags));

@ -460,7 +460,7 @@ static void ShutdownGame()
/* No NewGRFs were loaded when it was still bootstrapping. */
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
UninitFreeType();
UninitFontCache();
ViewportMapClearTunnelCache();
InvalidateVehicleTickCaches();
@ -884,8 +884,8 @@ int openttd_main(int argc, char *argv[])
/* enumerate language files */
InitializeLanguagePacks();
/* Initialize the regular font for FreeType */
InitFreeType(false);
/* Initialize the font cache */
InitFontCache(false);
/* This must be done early, since functions use the SetWindowDirty* calls */
InitWindowSystem();

@ -57,7 +57,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
}
if (os_err == noErr) {
DEBUG(freetype, 3, "Font path for %s: %s", font_name, file_path);
DEBUG(fontcache, 3, "Font path for %s: %s", font_name, file_path);
err = FT_New_Face(_library, (const char *)file_path, 0, face);
}
@ -67,7 +67,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
#endif /* WITH_FREETYPE */
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
{
/* Determine fallback font using CoreText. This uses the language isocode
* to find a suitable font. CoreText is available from 10.5 onwards. */
@ -134,7 +134,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
/* Save result. */
callback->SetFontNames(settings, name);
if (!callback->FindMissingGlyphs()) {
DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
DEBUG(fontcache, 2, "CT-Font for %s: %s", language_isocode, name);
result = true;
break;
}
@ -223,7 +223,7 @@ void CoreTextFontCache::SetFontSize(int pixels)
CFStringGetCString(font_name.get(), name, lengthof(name), kCFStringEncodingUTF8);
this->font_name = name;
DEBUG(freetype, 2, "Loaded font '%s' with size %d", this->font_name.c_str(), pixels);
DEBUG(fontcache, 2, "Loaded font '%s' with size %d", this->font_name.c_str(), pixels);
}
GlyphID CoreTextFontCache::MapCharToGlyph(WChar key)
@ -352,13 +352,13 @@ void LoadCoreTextFont(FontSize fs)
{
static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
FreeTypeSubSetting *settings = nullptr;
FontCacheSubSetting *settings = nullptr;
switch (fs) {
default: NOT_REACHED();
case FS_SMALL: settings = &_freetype.small; break;
case FS_NORMAL: settings = &_freetype.medium; break;
case FS_LARGE: settings = &_freetype.large; break;
case FS_MONO: settings = &_freetype.mono; break;
case FS_SMALL: settings = &_fcsettings.small; break;
case FS_NORMAL: settings = &_fcsettings.medium; break;
case FS_LARGE: settings = &_fcsettings.large; break;
case FS_MONO: settings = &_fcsettings.mono; break;
}
if (settings->font.empty()) return;

@ -10,7 +10,7 @@
#ifndef FONT_OSX_H
#define FONT_OSX_H
#include "../../fontcache_internal.h"
#include "../../fontcache/truetypefontcache.h"
#include "os/macosx/macos.h"
#include <CoreFoundation/CoreFoundation.h>

@ -94,7 +94,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
#endif /* WITH_FREETYPE */
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
{
if (!FcInit()) return false;
@ -148,7 +148,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
callback->SetFontNames(settings, (const char *)file);
bool missing = callback->FindMissingGlyphs();
DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
DEBUG(fontcache, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
if (!missing) {
best_weight = value;
@ -159,7 +159,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
if (best_font != nullptr) {
ret = true;
callback->SetFontNames(settings, best_font);
InitFreeType(callback->Monospace());
InitFontCache(callback->Monospace());
}
/* Clean up the list of filenames. */

@ -9,16 +9,17 @@
#include "../../stdafx.h"
#include "../../debug.h"
#include "font_win32.h"
#include "../../blitter/factory.hpp"
#include "../../core/alloc_func.hpp"
#include "../../core/math_func.hpp"
#include "../../fileio_func.h"
#include "../../fontdetection.h"
#include "../../fontcache.h"
#include "../../fontcache/truetypefontcache.h"
#include "../../string_func.h"
#include "../../strings_func.h"
#include "../../zoom_func.h"
#include "font_win32.h"
#include "../../table/control_codes.h"
@ -78,7 +79,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FONT_DIR_NT, 0, KEY_READ, &hKey);
if (ret != ERROR_SUCCESS) {
DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
DEBUG(fontcache, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
return err;
}
@ -113,7 +114,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
}
if (!SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, vbuffer))) {
DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
DEBUG(fontcache, 0, "SHGetFolderPath cannot return fonts directory");
goto folder_error;
}
@ -161,7 +162,7 @@ registry_no_font_found:
* @param logfont the font information to get the english name of.
* @return the English name (if it could be found).
*/
static const char *GetEnglishFontName(const ENUMLOGFONTEX *logfont)
static std::string GetEnglishFontName(const ENUMLOGFONTEX *logfont)
{
static char font_name[MAX_PATH];
const char *ret_font_name = nullptr;
@ -228,7 +229,7 @@ err2:
ReleaseDC(nullptr, dc);
DeleteObject(font);
err1:
return ret_font_name == nullptr ? FS2OTTD((const wchar_t *)logfont->elfFullName) : ret_font_name;
return ret_font_name == nullptr ? FS2OTTD((const wchar_t *)logfont->elfFullName) : std::string(ret_font_name);
}
#endif /* WITH_FREETYPE */
@ -268,7 +269,7 @@ public:
};
struct EFCParam {
FreeTypeSettings *settings;
FontCacheSettings *settings;
LOCALESIGNATURE locale;
MissingGlyphSearcher *callback;
FontList fonts;
@ -309,8 +310,8 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
#ifdef WITH_FREETYPE
/* Add english name after font name */
const char *english_name = GetEnglishFontName(logfont);
strecpy(font_name + strlen(font_name) + 1, english_name, lastof(font_name));
std::string english_name = GetEnglishFontName(logfont);
strecpy(font_name + strlen(font_name) + 1, english_name.c_str(), lastof(font_name));
/* Check whether we can actually load the font. */
bool ft_init = _library != nullptr;
@ -334,17 +335,17 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
info->callback->SetFontNames(info->settings, font_name, &logfont->elfLogFont);
if (info->callback->FindMissingGlyphs()) return 1;
DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
DEBUG(fontcache, 1, "Fallback font: %s (%s)", font_name, english_name);
return 0; // stop enumerating
}
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
{
DEBUG(freetype, 1, "Trying fallback fonts");
DEBUG(fontcache, 1, "Trying fallback fonts");
EFCParam langInfo;
if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
/* Invalid langid or some other mysterious error, can't determine fallback font. */
DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
DEBUG(fontcache, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
return false;
}
langInfo.settings = settings;
@ -441,7 +442,7 @@ void Win32FontCache::SetFontSize(FontSize fs, int pixels)
font_height_cache[this->fs] = this->GetHeight();
DEBUG(freetype, 2, "Loaded font '%s' with size %d", FS2OTTD((LPWSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)).c_str(), pixels);
DEBUG(fontcache, 2, "Loaded font '%s' with size %d", FS2OTTD((LPWSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)).c_str(), pixels);
}
/**
@ -581,12 +582,12 @@ void LoadWin32Font(FontSize fs)
{
static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
FreeTypeSubSetting *settings = nullptr;
FontCacheSubSetting *settings = nullptr;
switch (fs) {
case FS_SMALL: settings = &_freetype.small; break;
case FS_NORMAL: settings = &_freetype.medium; break;
case FS_LARGE: settings = &_freetype.large; break;
case FS_MONO: settings = &_freetype.mono; break;
case FS_SMALL: settings = &_fcsettings.small; break;
case FS_NORMAL: settings = &_fcsettings.medium; break;
case FS_LARGE: settings = &_fcsettings.large; break;
case FS_MONO: settings = &_fcsettings.mono; break;
default: NOT_REACHED();
}

@ -10,7 +10,7 @@
#ifndef FONT_WIN32_H
#define FONT_WIN32_H
#include "../../fontcache_internal.h"
#include "../../fontcache/truetypefontcache.h"
#include "win32.h"
/** Font cache for fonts that are based on a Win32 font. */

@ -2400,7 +2400,7 @@ const char *GetCurrentLanguageIsoCode()
*/
bool MissingGlyphSearcher::FindMissingGlyphs()
{
InitFreeType(this->Monospace());
InitFontCache(this->Monospace());
const Sprite *question_mark[FS_END];
for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
@ -2425,7 +2425,7 @@ bool MissingGlyphSearcher::FindMissingGlyphs()
default: NOT_REACHED();
}
DEBUG(freetype, 0, "Font is missing glyphs to display char 0x%X in %s font size", c, size_name.c_str());
DEBUG(fontcache, 0, "Font is missing glyphs to display char 0x%X in %s font size", c, size_name.c_str());
return true;
}
}
@ -2469,7 +2469,7 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
return false;
}
void SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data) override
void SetFontNames(FontCacheSettings *settings, const char *font_name, const void *os_data) override
{
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
settings->small.font = font_name;
@ -2505,15 +2505,15 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
if (bad_font) {
/* We found an unprintable character... lets try whether we can find
* a fallback font that can print the characters in the current language. */
bool any_font_configured = !_freetype.medium.font.empty();
FreeTypeSettings backup = _freetype;
bool any_font_configured = !_fcsettings.medium.font.empty();
FontCacheSettings backup = _fcsettings;
_freetype.mono.os_handle = nullptr;
_freetype.medium.os_handle = nullptr;
_fcsettings.mono.os_handle = nullptr;
_fcsettings.medium.os_handle = nullptr;
bad_font = !SetFallbackFont(&_freetype, _langpack.langpack->isocode, _langpack.langpack->winlangid, searcher);
bad_font = !SetFallbackFont(&_fcsettings, _langpack.langpack->isocode, _langpack.langpack->winlangid, searcher);
_freetype = backup;
_fcsettings = backup;
if (!bad_font && any_font_configured) {
/* If the user configured a bad font, and we found a better one,
@ -2532,7 +2532,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
/* Our fallback font does miss characters too, so keep the
* user chosen font as that is more likely to be any good than
* the wild guess we made */
InitFreeType(searcher->Monospace());
InitFontCache(searcher->Monospace());
}
}
#endif

@ -276,7 +276,7 @@ public:
* @param font_name The new font name.
* @param os_data Opaque pointer to OS-specific data.
*/
virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name, const void *os_data = nullptr) = 0;
virtual void SetFontNames(struct FontCacheSettings *settings, const char *font_name, const void *os_data = nullptr) = 0;
bool FindMissingGlyphs();
};

@ -190,35 +190,35 @@ def = false
ifdef = HAS_TRUETYPE_FONT
name = ""small_font""
type = SLE_STR
var = _freetype.small.font
var = _fcsettings.small.font
def = nullptr
[SDTG_SSTR]
ifdef = HAS_TRUETYPE_FONT
name = ""medium_font""
type = SLE_STR
var = _freetype.medium.font
var = _fcsettings.medium.font
def = nullptr
[SDTG_SSTR]
ifdef = HAS_TRUETYPE_FONT
name = ""large_font""
type = SLE_STR
var = _freetype.large.font
var = _fcsettings.large.font
def = nullptr
[SDTG_SSTR]
ifdef = HAS_TRUETYPE_FONT
name = ""mono_font""
type = SLE_STR
var = _freetype.mono.font
var = _fcsettings.mono.font
def = nullptr
[SDTG_VAR]
ifdef = HAS_TRUETYPE_FONT
name = ""small_size""
type = SLE_UINT
var = _freetype.small.size
var = _fcsettings.small.size
def = 0
min = 0
max = 72
@ -227,7 +227,7 @@ max = 72
ifdef = HAS_TRUETYPE_FONT
name = ""medium_size""
type = SLE_UINT
var = _freetype.medium.size
var = _fcsettings.medium.size
def = 0
min = 0
max = 72
@ -236,7 +236,7 @@ max = 72
ifdef = HAS_TRUETYPE_FONT
name = ""large_size""
type = SLE_UINT
var = _freetype.large.size
var = _fcsettings.large.size
def = 0
min = 0
max = 72
@ -245,7 +245,7 @@ max = 72
ifdef = HAS_TRUETYPE_FONT
name = ""mono_size""
type = SLE_UINT
var = _freetype.mono.size
var = _fcsettings.mono.size
def = 0
min = 0
max = 72
@ -253,25 +253,25 @@ max = 72
[SDTG_BOOL]
ifdef = HAS_TRUETYPE_FONT
name = ""small_aa""
var = _freetype.small.aa
var = _fcsettings.small.aa
def = false
[SDTG_BOOL]
ifdef = HAS_TRUETYPE_FONT
name = ""medium_aa""
var = _freetype.medium.aa
var = _fcsettings.medium.aa
def = false
[SDTG_BOOL]
ifdef = HAS_TRUETYPE_FONT
name = ""large_aa""
var = _freetype.large.aa
var = _fcsettings.large.aa
def = false
[SDTG_BOOL]
ifdef = HAS_TRUETYPE_FONT
name = ""mono_aa""
var = _freetype.mono.aa
var = _fcsettings.mono.aa
def = false
[SDTG_VAR]

@ -17,7 +17,7 @@ static const byte CLRA = 0; ///< Identifier to clear all glyphs at this codepoin
/* Default unicode mapping table for sprite based glyphs.
* This table allows us use unicode characters even though the glyphs don't
* exist, or are in the wrong place, in the standard sprite fonts.
* This is not used for FreeType rendering */
* This is not used for TrueType rendering */
static const DefaultUnicodeMapping _default_unicode_map[] = {
{ 0x00A0, 0x20 }, // Non-breaking space / Up arrow

@ -215,7 +215,7 @@ void TextfileWindow::SetupScrollbars(bool force_reflow)
return true;
}
/* virtual */ void TextfileWindow::SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data)
/* virtual */ void TextfileWindow::SetFontNames(FontCacheSettings *settings, const char *font_name, const void *os_data)
{
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
settings->mono.font = font_name;

@ -52,7 +52,7 @@ struct TextfileWindow : public Window, MissingGlyphSearcher {
FontSize DefaultSize() override;
const char *NextString() override;
bool Monospace() override;
void SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data) override;
void SetFontNames(FontCacheSettings *settings, const char *font_name, const void *os_data) override;
virtual void LoadTextfile(const char *textfile, Subdirectory dir);

@ -1175,7 +1175,6 @@ static CallBackFunction ToolbarScenDatePanel(Window *w)
{
SetDParam(0, _settings_game.game_creation.starting_year);
ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
_left_button_clicked = false;
return CBF_NONE;
}

@ -1275,7 +1275,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
driver->AllocateBackingStore();
}
/** Presentation options to use for fullsreen mode. */
/** Presentation options to use for full screen mode. */
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
{
return NSApplicationPresentationFullScreen | NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock;

@ -3116,7 +3116,7 @@ void HandleMouseEvents()
hover_pos = _cursor.pos;
hover_time = std::chrono::steady_clock::now();
_mouse_hovering = false;
} else {
} else if (!_mouse_hovering) {
if (std::chrono::steady_clock::now() > hover_time + std::chrono::milliseconds(_settings_client.gui.hover_delay_ms)) {
click = MC_HOVER;
_input_events_this_tick++;

Loading…
Cancel
Save