1
0
Fork 0

Compare commits

..

No commits in common. "53fa54f8e9babc3a28226a1f7e7ec6478431e558" and "71aaed860b092f2ca8da48ff1eb50c71ac57b68d" have entirely different histories.

43 changed files with 237 additions and 429 deletions

View File

@ -56,7 +56,6 @@
- George - Canal/Lock graphics
- Andrew Parkhouse (andythenorth) - River graphics
- David Dallaston (Pikka) - Tram tracks
- Richard Wheeler (zephyris) - OpenTTD TrueType font
- All Translators - For their support to make OpenTTD a truly international game
- Bug Reporters - Thanks for all bug reports
- Chris Sawyer - For an amazing game!

View File

@ -16,6 +16,7 @@
.Op Fl g Op Ar savegame
.Op Fl G Ar seed
.Op Fl I Ar graphicsset
.Op Fl l Ar host Ns Op : Ns Ar port
.Op Fl m Ar driver
.Op Fl M Ar musicset
.Op Fl n Ar host Ns Oo : Ns Ar port Oc Ns Op # Ns Ar company
@ -81,6 +82,9 @@ Select the graphics set
see
.Fl h
for a full list.
.It Fl l Ar host Ns Op : Ns Ar port
Redirect debug output; see
.Fl d .
.It Fl m Ar driver
Select the music driver
.Ar driver ;

View File

@ -18,10 +18,6 @@ set(BASESET_OTHER_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/opntitle.dat
${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf
${CMAKE_CURRENT_SOURCE_DIR}/../openttd.32.bmp
${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Sans.ttf
${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Serif.ttf
${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Small.ttf
${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Mono.ttf
)
# Done by the subdirectories, if nforenum / grfcodec is installed
@ -67,7 +63,7 @@ foreach(BASESET_OTHER_SOURCE_FILE IN LISTS BASESET_OTHER_SOURCE_FILES)
get_filename_component(BASESET_OTHER_SOURCE_FILE_NAME "${BASESET_OTHER_SOURCE_FILE}" NAME)
set(BASESET_OTHER_BINARY_FILE "${CMAKE_BINARY_DIR}/baseset/${BASESET_OTHER_SOURCE_FILE_NAME}")
add_custom_command_timestamp(OUTPUT ${BASESET_OTHER_BINARY_FILE}
add_custom_command(OUTPUT ${BASESET_OTHER_BINARY_FILE}
COMMAND ${CMAKE_COMMAND} -E copy
${BASESET_OTHER_SOURCE_FILE}
${BASESET_OTHER_BINARY_FILE}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +0,0 @@
# OpenTTD TrueType font
The OpenTTD TrueType font was created by Zephyris and is maintained on [Github](https://github.com/zephyris/openttd-ttf).
It is licensed under GPL-2.0.
The currently included files correspond to release v0.3.

View File

@ -106,7 +106,7 @@ void IConsolePrint(TextColour colour_code, const std::string &string)
/* Create a copy of the string, strip it of colours and invalid
* characters and (when applicable) assign it to the console buffer */
std::string str = StrMakeValid(string, SVS_NONE);
std::string str = StrMakeValid(string);
if (_network_dedicated) {
NetworkAdminConsole("console", str);

View File

@ -22,6 +22,7 @@
#include "3rdparty/fmt/chrono.h"
#include "network/network_admin.h"
SOCKET _debug_socket = INVALID_SOCKET;
#include "safeguards.h"
@ -110,6 +111,18 @@ void DumpDebugFacilityNames(std::back_insert_iterator<std::string> &output_itera
*/
void DebugPrint(const char *level, const std::string &message)
{
if (_debug_socket != INVALID_SOCKET) {
std::string msg = fmt::format("{}dbg: [{}] {}\n", GetLogPrefix(), level, message);
/* Prevent sending a message concurrently, as that might cause interleaved messages. */
static std::mutex _debug_socket_mutex;
std::lock_guard<std::mutex> lock(_debug_socket_mutex);
/* Sending out an error when this fails would be nice, however... the error
* would have to be send over this failing socket which won't work. */
send(_debug_socket, msg.c_str(), (int)msg.size(), 0);
return;
}
if (strcmp(level, "desync") == 0) {
static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
if (f == nullptr) return;

View File

@ -18,7 +18,6 @@
#include "strings_func.h"
#include "viewport_func.h"
#include "window_func.h"
#include "fileio_func.h"
#include "safeguards.h"
@ -96,7 +95,7 @@ bool GetFontAAState(FontSize size, bool check_blitter)
/* AA is only supported for 32 bpp */
if (check_blitter && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
return _fcsettings.global_aa || GetFontCacheSubSetting(size)->aa;
return GetFontCacheSubSetting(size)->aa;
}
void SetFont(FontSize fontsize, const std::string &font, uint size, bool aa)
@ -144,52 +143,13 @@ void SetFont(FontSize fontsize, const std::string &font, uint size, bool aa)
#ifdef WITH_FREETYPE
extern void LoadFreeTypeFont(FontSize fs);
extern void LoadFreeTypeFont(FontSize fs, const std::string &file_name, uint size);
extern void UninitFreeType();
#elif defined(_WIN32)
extern void LoadWin32Font(FontSize fs);
extern void LoadWin32Font(FontSize fs, const std::string &file_name, uint size);
#elif defined(WITH_COCOA)
extern void LoadCoreTextFont(FontSize fs);
extern void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size);
#endif
static void TryLoadDefaultTrueTypeFont([[maybe_unused]] FontSize fs)
{
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
std::string font_name{};
switch (fs) {
case FS_NORMAL:
font_name = "OpenTTD-Sans.ttf";
break;
case FS_SMALL:
font_name = "OpenTTD-Small.ttf";
break;
case FS_LARGE:
font_name = "OpenTTD-Serif.ttf";
break;
case FS_MONO:
font_name = "OpenTTD-Mono.ttf";
break;
default: NOT_REACHED();
}
/* Find font file. */
std::string full_font = FioFindFullPath(BASESET_DIR, font_name);
if (!full_font.empty()) {
int size = FontCache::GetDefaultFontHeight(fs);
#ifdef WITH_FREETYPE
LoadFreeTypeFont(fs, full_font, size);
#elif defined(_WIN32)
LoadWin32Font(fs, full_font, size);
#elif defined(WITH_COCOA)
LoadCoreTextFont(fs, full_font, size);
#endif
}
#endif /* defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) */
}
/**
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
* @param monospace Whether to initialise the monospace or regular fonts.
@ -204,17 +164,13 @@ void InitFontCache(bool monospace)
FontCache *fc = FontCache::Get(fs);
if (fc->HasParent()) delete fc;
if (!_fcsettings.prefer_sprite && GetFontCacheSubSetting(fs)->font.empty()) {
TryLoadDefaultTrueTypeFont(fs);
} else {
#ifdef WITH_FREETYPE
LoadFreeTypeFont(fs);
LoadFreeTypeFont(fs);
#elif defined(_WIN32)
LoadWin32Font(fs);
LoadWin32Font(fs);
#elif defined(WITH_COCOA)
LoadCoreTextFont(fs);
LoadCoreTextFont(fs);
#endif
}
}
}

View File

@ -108,10 +108,9 @@ public:
/**
* Map a character into a glyph.
* @param key The character.
* @param fallback Allow fallback to the parent font.
* @return The glyph ID used to draw the character.
*/
virtual GlyphID MapCharToGlyph(char32_t key, bool fallback = true) = 0;
virtual GlyphID MapCharToGlyph(char32_t key) = 0;
/**
* Read a font table from the font.
@ -218,8 +217,6 @@ struct FontCacheSettings {
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.
bool prefer_sprite; ///< Whether to prefer the built-in sprite font over resizable fonts.
bool global_aa; ///< Whether to anti alias all font sizes.
};
extern FontCacheSettings _fcsettings;

View File

@ -41,7 +41,7 @@ public:
FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
~FreeTypeFontCache();
void ClearFontCache() override;
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
GlyphID MapCharToGlyph(char32_t key) override;
std::string GetFontName() override { return fmt::format("{}, {}", face->family_name, face->style_name); }
bool IsBuiltInFont() override { return false; }
const void *GetOSHandle() override { return &face; }
@ -115,42 +115,6 @@ void FreeTypeFontCache::SetFontSize(FontSize, FT_Face, int pixels)
}
}
static FT_Error LoadFont(FontSize fs, FT_Face face, const char *font_name, uint size)
{
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
/* Attempt to select the unicode character map */
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
if (error == FT_Err_Ok) goto found_face; // Success
if (error == FT_Err_Invalid_CharMap_Handle) {
/* Try to pick a different character map instead. We default to
* the first map, but platform_id 0 encoding_id 0 should also
* be unicode (strange system...) */
FT_CharMap found = face->charmaps[0];
int i;
for (i = 0; i < face->num_charmaps; i++) {
FT_CharMap charmap = face->charmaps[i];
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
found = charmap;
}
}
if (found != nullptr) {
error = FT_Set_Charmap(face, found);
if (error == FT_Err_Ok) goto found_face;
}
}
FT_Done_Face(face);
return error;
found_face:
new FreeTypeFontCache(fs, face, size);
return FT_Err_Ok;
}
/**
* Loads the freetype font.
* First type to load the fontname as if it were a path. If that fails,
@ -193,40 +157,40 @@ void LoadFreeTypeFont(FontSize fs)
if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, &face);
if (error == FT_Err_Ok) {
error = LoadFont(fs, face, font_name, settings->size);
if (error != FT_Err_Ok) {
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
/* Attempt to select the unicode character map */
error = FT_Select_Charmap(face, ft_encoding_unicode);
if (error == FT_Err_Ok) goto found_face; // Success
if (error == FT_Err_Invalid_CharMap_Handle) {
/* Try to pick a different character map instead. We default to
* the first map, but platform_id 0 encoding_id 0 should also
* be unicode (strange system...) */
FT_CharMap found = face->charmaps[0];
int i;
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;
}
}
} else {
FT_Done_Face(face);
}
}
/**
* Load a TrueType font from a file.
* @param fs The font size to load.
* @param file_name Path to the font file.
* @param size Requested font size.
*/
void LoadFreeTypeFont(FontSize fs, const std::string &file_name, uint size)
{
if (_library == nullptr) {
if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
return;
}
Debug(fontcache, 2, "Initialized");
}
FT_Face face = nullptr;
int32_t index = 0;
FT_Error error = FT_New_Face(_library, file_name.c_str(), index, &face);
if (error == FT_Err_Ok) {
LoadFont(fs, face, file_name.c_str(), size);
} else {
FT_Done_Face(face);
}
FT_Done_Face(face);
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
return;
found_face:
new FreeTypeFontCache(fs, face, settings->size);
}
@ -312,17 +276,15 @@ const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa)
}
GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key)
{
assert(IsPrintable(key));
FT_UInt glyph = FT_Get_Char_Index(this->face, key);
if (glyph == 0 && allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
return this->parent->MapCharToGlyph(key);
}
return glyph;
return FT_Get_Char_Index(this->face, key);
}
const void *FreeTypeFontCache::InternalGetFontTable(uint32_t tag, size_t &length)

View File

@ -29,7 +29,7 @@ public:
const Sprite *GetGlyph(GlyphID key) override;
uint GetGlyphWidth(GlyphID key) override;
bool GetDrawGlyphShadow() override;
GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; }
GlyphID MapCharToGlyph(char32_t key) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; }
const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; }
std::string GetFontName() override { return "sprite"; }
bool IsBuiltInFont() override { return true; }

View File

@ -579,8 +579,6 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
bool draw_shadow = false;
for (int run_index = 0; run_index < line.CountRuns(); run_index++) {
const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index);
const auto &glyphs = run.GetGlyphs();
const auto &positions = run.GetPositions();
const Font *f = run.GetFont();
FontCache *fc = f->fc;
@ -594,14 +592,14 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
draw_shadow = fc->GetDrawGlyphShadow() && (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
for (int i = 0; i < run.GetGlyphCount(); i++) {
GlyphID glyph = glyphs[i];
GlyphID glyph = run.GetGlyphs()[i];
/* Not a valid glyph (empty) */
if (glyph == 0xFFFF) continue;
int begin_x = (int)positions[i * 2] + left - offset_x;
int end_x = (int)positions[i * 2 + 2] + left - offset_x - 1;
int top = (int)positions[i * 2 + 1] + y;
int begin_x = (int)run.GetPositions()[i * 2] + left - offset_x;
int end_x = (int)run.GetPositions()[i * 2 + 2] + left - offset_x - 1;
int top = (int)run.GetPositions()[i * 2 + 1] + y;
/* Truncated away. */
if (truncation && (begin_x < min_x || end_x > max_x)) continue;
@ -1779,10 +1777,6 @@ bool ToggleFullScreen(bool fs)
void SortResolutions()
{
std::sort(_resolutions.begin(), _resolutions.end());
/* Remove any duplicates from the list. */
auto last = std::unique(_resolutions.begin(), _resolutions.end());
_resolutions.erase(last, _resolutions.end());
}
/**

View File

@ -254,13 +254,11 @@ Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const
/* Scan all runs until we've found our code point index. */
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index);
const auto &positions = run.GetPositions();
const auto &charmap = run.GetGlyphToCharMap();
for (int i = 0; i < run.GetGlyphCount(); i++) {
/* Matching glyph? Return position. */
if ((size_t)charmap[i] == index) {
Point p = { (int)positions[i * 2], (int)positions[i * 2 + 1] };
if ((size_t)run.GetGlyphToCharMap()[i] == index) {
Point p = { (int)run.GetPositions()[i * 2], (int)run.GetPositions()[i * 2 + 1] };
return p;
}
}
@ -283,20 +281,17 @@ ptrdiff_t Layouter::GetCharAtPosition(int x, size_t line_index) const
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index);
const auto &glyphs = run.GetGlyphs();
const auto &positions = run.GetPositions();
const auto &charmap = run.GetGlyphToCharMap();
for (int i = 0; i < run.GetGlyphCount(); i++) {
/* Not a valid glyph (empty). */
if (glyphs[i] == 0xFFFF) continue;
if (run.GetGlyphs()[i] == 0xFFFF) continue;
int begin_x = (int)positions[i * 2];
int end_x = (int)positions[i * 2 + 2];
int begin_x = (int)run.GetPositions()[i * 2];
int end_x = (int)run.GetPositions()[i * 2 + 2];
if (IsInsideMM(x, begin_x, end_x)) {
/* Found our glyph, now convert to UTF-8 string index. */
size_t index = charmap[i];
size_t index = run.GetGlyphToCharMap()[i];
size_t cur_idx = 0;
for (auto str = this->string.begin(); str != this->string.end();) {

View File

@ -193,7 +193,7 @@ void ICURun::Shape(UChar *buff, size_t buff_length)
for (unsigned int i = 0; i < glyph_count; i++) {
int x_advance;
if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END && glyph_info[i].codepoint == 0) {
if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END) {
auto glyph = this->font->fc->MapCharToGlyph(buff[glyph_info[i].cluster]);
this->glyphs.push_back(glyph);

View File

@ -43,38 +43,25 @@ void ShowHeightmapLoad();
/* misc_gui.cpp */
void ShowLandInfo(TileIndex tile);
void ShowAboutWindow();
void ShowEstimatedCostOrIncome(Money cost, int x, int y);
/* tree_gui.cpp */
void ShowBuildTreesToolbar();
/* town_gui.cpp */
void ShowTownDirectory();
void ShowFoundTownWindow();
/* industry_gui.cpp */
void ShowIndustryDirectory();
void ShowIndustryCargoesWindow();
void ShowBuildIndustryWindow();
/* subsidy_gui.cpp */
void ShowSubsidiesList();
/* goal_gui.cpp */
void ShowGoalsList(CompanyID company);
void ShowGoalQuestion(uint16_t id, byte type, uint32_t button_mask, const std::string &question);
/* story_gui.cpp */
void ShowStoryBook(CompanyID company, uint16_t page_id = INVALID_STORY_PAGE);
/* viewport_gui.cpp */
void ShowEstimatedCostOrIncome(Money cost, int x, int y);
void ShowExtraViewportWindow(TileIndex tile = INVALID_TILE);
void ShowExtraViewportWindowForTileUnderCursor();
/* bridge_gui.cpp */
void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte bridge_type);
/* music_gui.cpp */
void ShowBuildIndustryWindow();
void ShowFoundTownWindow();
void ShowMusicWindow();
#endif /* GUI_H */

View File

@ -1002,7 +1002,6 @@ STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dolla
STR_GAME_OPTIONS_CURRENCY_INR :Indisk rupi
STR_GAME_OPTIONS_CURRENCY_IDR :Indonesisk Rupiah
STR_GAME_OPTIONS_CURRENCY_MYR :Malaysisk Ringgit
STR_GAME_OPTIONS_CURRENCY_LVL :lettiske lats
STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Automatisk gemning
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Vælg interval imellem automatisk gemning
@ -3017,7 +3016,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Ejer af
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokal myndighed: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ingen
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Bygget/renoveret: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Produceret: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stationsklasse: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stationstype: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Lufthavnsklasse: {LTBLUE}{STRING}

View File

@ -1044,11 +1044,6 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Check th
STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Scale bevels
STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Check this box to scale bevels by interface size
STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Use traditional sprite font
STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Check this box if you prefer to use the tradition fixed-size sprite font.
STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Anti-alias fonts
STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Check this box to anti-alias resizable fonts.
STR_GAME_OPTIONS_GUI_SCALE_1X :1x
STR_GAME_OPTIONS_GUI_SCALE_2X :2x
STR_GAME_OPTIONS_GUI_SCALE_3X :3x

View File

@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built/renovated: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING}

View File

@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railroad
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Co-ordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built/renovated: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING}

View File

@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Rautatie
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Kunta: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ei mitään
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaatit: {LTBLUE}{NUM}×{NUM}×{NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Rakennettu/peruskorjattu: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Rakennettu: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Aseman luokka: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Aseman tyyppi: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Lentokentän luokka: {LTBLUE}{STRING}

View File

@ -1003,7 +1003,7 @@ STR_GAME_OPTIONS_CURRENCY_HKD :Dollar de Hong
STR_GAME_OPTIONS_CURRENCY_INR :Roupie indienne
STR_GAME_OPTIONS_CURRENCY_IDR :Roupie indonésienne
STR_GAME_OPTIONS_CURRENCY_MYR :Malaysian Ringgit
STR_GAME_OPTIONS_CURRENCY_LVL :Lats letton
STR_GAME_OPTIONS_CURRENCY_LVL :Lats
STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Sauvegarde automatique
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Sélectionner l'intervalle de temps entre les sauvegardes automatiques
@ -3018,7 +3018,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Proprié
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Municipalité{NBSP}: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Aucune
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordonnées{NBSP}: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construit/rénové le{NBSP}: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construit le{NBSP}: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Type de station{NBSP}: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Type de station{NBSP}: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Type d'aéroport{NBSP}: {LTBLUE}{STRING}

View File

@ -2727,7 +2727,7 @@ STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}자동
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}차량기지를 건설합니다. 차량을 구입하거나 점검을 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}선로에 경유지를 설치합니다. CTRL 키를 사용하면 같은 이름의 경유지를 서로 떨어진 곳에 지을 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}철도역을 짓습니다. CTRL 키를 사용하면 같은 이름의 역을 서로 떨어진 곳에 지을 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}선로에 신호기를 설치합니다. CTRL 키를 누르면 구식/전자식으로 전환합니다.{}선로를 따라 드래그해서 설치할 수 있습니다. CTRL 키를 누른 채로 드래그하면 다음 분기점이나 다음 신호기까지 신호기를 설치합니다.{}CTRL 키를 누른 채 클릭하면 신호기 선택 창을 전환합니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}신호기를 설치합니다. CTRL 키를 누르면 구식/전자식으로 전환합니다.{}선로를 따라 드래그해서 설치할 수 있습니다. CTRL 키를 누른 채로 드래그하면 다음 분기점이나 다음 신호기까지 신호기를 설치합니다.{}CTRL 키를 누른 채 클릭하면 신호기 선택 창을 전환합니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}철교를 짓습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}터널을 짓습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다
STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}선로, 신호기, 경유지, 역 등의 철도 시설 건설/철거 모드를 켜거나 끌 수 있습니다. CTRL 키를 누르고 있어도 선로에서 경유지와 역을 제거할 수 있습니다

View File

@ -3018,7 +3018,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dono da
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoridade local: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nenhum
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construído/renovado: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construído: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Tipo de estação: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de estação: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Tipo de aeroporto: {LTBLUE}{STRING}

View File

@ -3192,7 +3192,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Влад
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Администрация: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Нет
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координаты: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Построено/обновлено: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Построено: {LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Класс станции: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Тип станции: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Класс аэропорта: {LTBLUE}{STRING.nom}

View File

@ -350,7 +350,7 @@ STR_SORT_BY_CARGO_CAPACITY :运载能力
STR_SORT_BY_RANGE :航行距离
STR_SORT_BY_POPULATION :人口
STR_SORT_BY_RATING :评价
STR_SORT_BY_NUM_VEHICLES :具数量
STR_SORT_BY_NUM_VEHICLES :交通工具数量
STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :去年总利润
STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :今年总利润
STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :去年平均利润
@ -1325,7 +1325,7 @@ STR_CONFIG_SETTING_PERCENTAGE :{COMMA}%
STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :汽车斜坡坡度: {STRING}
STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :设置对汽车而言,一格斜坡的坡度大小。数值越高,坡度越大,汽车越难爬上斜坡。
STR_CONFIG_SETTING_FORBID_90_DEG :禁止列车直角转向{STRING}
STR_CONFIG_SETTING_FORBID_90_DEG :禁止列车 90 度转弯{STRING}
STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :当水平方向轨道与垂直方向轨道交叉时没有采用45度的轨道组合连接而是采用轨道90度直接连接时列车通过时需要90度转弯当本设置”打开“时将禁止火车90度转弯。
STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :允许非毗邻站台合并:{STRING}
@ -1344,7 +1344,7 @@ STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :隧道最大长
STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :建设隧道时允许的最大长度
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :原料工业建设方式: {STRING}
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :设定原料工业的建造方式。“禁止”表示不能建造;“勘探”表示可以建立但是只能在地图上一随机处,并可能会失败;“同其他工业”表示可以和随意建造。
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :建立重工业企业的的设定. '禁止'表示不能建立; '勘探'表示可以建立但是只能在地图上一随机处, 并可能会失败; '像别的工业一样'表示采矿业也能像其它加工业那样可以随意在任何地方建立.
###length 3
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :不允许
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :同其他工业
@ -1911,7 +1911,7 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :四倍(原版
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :线性
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :树木自动生长: {STRING}
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :控制游戏内树木的生长。此选项可能会影响一些依赖树木的工业,例如伐木场。
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :控制游戏中数目的随机生长,这将影响依赖树木的工业,比如木材厂
###length 4
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :生长但不扩散 {RED}(损坏伐木场)
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :仅在雨林扩散
@ -2826,7 +2826,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}建设/
STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}转换/升级 公路类型。按住 Shift 键显示预计费用。
STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :转换/升级 电车道类型。按住 Shift 键显示预计费用。
STR_ROAD_NAME_ROAD :
STR_ROAD_NAME_ROAD :路
STR_ROAD_NAME_TRAM :电车轨道
# Road depot construction window
@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}铁路
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}地方政府:{LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :没有
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}坐标: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}建造/翻新于{LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}建造时间{LTBLUE}{DATE_LONG}
STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}车站分类: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}车站类型: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}飞机场分类: {LTBLUE}{STRING}
@ -3246,7 +3246,7 @@ STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}%
STR_MAPGEN_TERRAIN_TYPE :{BLACK}地形特点:
STR_MAPGEN_SEA_LEVEL :{BLACK}海洋面积:
STR_MAPGEN_SEA_LEVEL_TOOLTIP :{BLACK}选择海洋覆盖率
STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}河流数量
STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}河流数量:
STR_MAPGEN_SMOOTHNESS :{BLACK}平滑程度:
STR_MAPGEN_VARIETY :{BLACK}多样地形:
STR_MAPGEN_GENERATE :{WHITE}生成
@ -3854,7 +3854,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}运河
STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}站台:
STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}车站
STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}机场
STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/年
STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}每年{CURRENCY_LONG}
# Industry directory
STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}工业设施
@ -5625,7 +5625,7 @@ STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut 直
# Formatting of some strings
STR_FORMAT_DATE_TINY :{ZEROFILL_NUM}-{ZEROFILL_NUM}-{NUM}
STR_FORMAT_DATE_SHORT :{STRING} {NUM}
STR_FORMAT_DATE_LONG :{2:NUM} 年 {1:STRING} 月 {0:STRING}
STR_FORMAT_DATE_LONG :{2:NUM}年 {1:STRING}月 {0:STRING}日
STR_FORMAT_DATE_ISO :{2:NUM}-{1:ZEROFILL_NUM}-{0:ZEROFILL_NUM}
STR_FORMAT_COMPANY_NUM :(公司 {COMMA})

View File

@ -24,6 +24,7 @@ static const uint16_t NETWORK_TURN_SERVER_PORT = 3974; ///< The
static const uint16_t NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP)
static const uint16_t NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP)
static const uint16_t NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
static const uint16_t NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP)
static const uint16_t UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet

View File

@ -1218,6 +1218,32 @@ static void NetworkGenerateServerId()
_settings_client.network.network_id = GenerateUid("OpenTTD Server ID");
}
class TCPNetworkDebugConnecter : TCPConnecter {
private:
std::string connection_string;
public:
TCPNetworkDebugConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT), connection_string(connection_string) {}
void OnFailure() override
{
Debug(net, 0, "Failed to open connection to {} for redirecting Debug()", this->connection_string);
}
void OnConnect(SOCKET s) override
{
Debug(net, 3, "Redirecting Debug() to {}", this->connection_string);
extern SOCKET _debug_socket;
_debug_socket = s;
}
};
void NetworkStartDebugLog(const std::string &connection_string)
{
new TCPNetworkDebugConnecter(connection_string);
}
/** This tries to launch the network for a given OS */
void NetworkStartUp()
{

View File

@ -47,6 +47,7 @@ void NetworkDisconnect(bool close_admins = true);
void NetworkGameLoop();
void NetworkBackgroundLoop();
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16_t &port, CompanyID *company_id = nullptr);
void NetworkStartDebugLog(const std::string &connection_string);
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
void NetworkUpdateClientInfo(ClientID client_id);

View File

@ -169,6 +169,7 @@ static void ShowHelp()
" -p password = Password to join server\n"
" -P password = Password to join company\n"
" -D [host][:port] = Start dedicated server\n"
" -l host[:port] = Redirect Debug()\n"
#if !defined(_WIN32)
" -f = Fork into the background (dedicated only)\n"
#endif
@ -488,6 +489,7 @@ static const OptionData _options[] = {
GETOPT_SHORT_VALUE('b'),
GETOPT_SHORT_OPTVAL('D'),
GETOPT_SHORT_VALUE('n'),
GETOPT_SHORT_VALUE('l'),
GETOPT_SHORT_VALUE('p'),
GETOPT_SHORT_VALUE('P'),
#if !defined(_WIN32)
@ -526,6 +528,7 @@ int openttd_main(int argc, char *argv[])
Dimension resolution = {0, 0};
std::unique_ptr<AfterNewGRFScan> scanner(new AfterNewGRFScan());
bool dedicated = false;
char *debuglog_conn = nullptr;
bool only_local_path = false;
extern bool _dedicated_forks;
@ -562,6 +565,9 @@ int openttd_main(int argc, char *argv[])
case 'n':
scanner->connection_string = mgo.opt; // host:port#company parameter
break;
case 'l':
debuglog_conn = mgo.opt;
break;
case 'p':
scanner->join_server_password = mgo.opt;
break;
@ -756,6 +762,10 @@ int openttd_main(int argc, char *argv[])
NetworkStartUp(); // initialize network-core
if (debuglog_conn != nullptr && _network_available) {
NetworkStartDebugLog(debuglog_conn);
}
if (!HandleBootstrap()) {
ShutdownGame();
return ret;

View File

@ -180,10 +180,14 @@ void CoreTextFontCache::SetFontSize(int pixels)
Debug(fontcache, 2, "Loaded font '{}' with size {}", this->font_name, pixels);
}
GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key)
{
assert(IsPrintable(key));
if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
return this->parent->MapCharToGlyph(key);
}
/* Convert characters outside of the Basic Multilingual Plane into surrogate pairs. */
UniChar chars[2];
if (key >= 0x010000U) {
@ -198,10 +202,6 @@ GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
return glyph[0];
}
if (allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
return this->parent->MapCharToGlyph(key);
}
return 0;
}
@ -298,40 +298,6 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
return new_glyph.sprite;
}
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
{
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
/* Might be a font file name, try load it. Direct font loading is
* only supported starting on OSX 10.6. */
CFAutoRelease<CFStringRef> path;
/* See if this is an absolute path. */
if (FileExists(font_name)) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
} else {
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
}
}
if (path) {
/* Try getting a font descriptor to see if the system can use it. */
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
if (descs && CFArrayGetCount(descs.get()) > 0) {
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
CFRetain(font_ref);
return font_ref;
}
}
return nullptr;
}
/**
* Loads the TrueType font.
* If a CoreText font description is present, e.g. from the automatic font
@ -352,9 +318,33 @@ void LoadCoreTextFont(FontSize fs)
}
if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
/* Might be a font file name, try load it. */
font_ref.reset(LoadFontFromFile(settings->font));
if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", settings->font, FontSizeToName(fs));
/* Might be a font file name, try load it. Direct font loading is
* only supported starting on OSX 10.6. */
CFAutoRelease<CFStringRef> path;
/* See if this is an absolute path. */
if (FileExists(settings->font)) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, settings->font.c_str(), kCFStringEncodingUTF8));
} else {
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, settings->font);
if (!full_font.empty()) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
}
}
if (path) {
/* Try getting a font descriptor to see if the system can use it. */
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
if (descs && CFArrayGetCount(descs.get()) > 0) {
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
CFRetain(font_ref.get());
} else {
ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", settings->font, FontSizeToName(fs));
}
}
}
if (!font_ref) {
@ -382,17 +372,3 @@ void LoadCoreTextFont(FontSize fs)
new CoreTextFontCache(fs, std::move(font_ref), settings->size);
}
/**
* Load a TrueType font from a file.
* @param fs The font size to load.
* @param file_name Path to the font file.
* @param size Requested font size.
*/
void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size)
{
CFAutoRelease<CTFontDescriptorRef> font_ref{LoadFontFromFile(file_name)};
if (font_ref) {
new CoreTextFontCache(fs, std::move(font_ref), size);
}
}

View File

@ -29,13 +29,12 @@ public:
~CoreTextFontCache() {}
void ClearFontCache() override;
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
GlyphID MapCharToGlyph(char32_t key) override;
std::string GetFontName() override { return font_name; }
bool IsBuiltInFont() override { return false; }
const void *GetOSHandle() override { return font.get(); }
};
void LoadCoreTextFont(FontSize fs);
void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size);
#endif /* FONT_OSX_H */

View File

@ -168,9 +168,6 @@ static CTRunDelegateCallbacks _sprite_font_callback = {
CFAutoRelease<CFStringRef> base(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buff, length, kCFAllocatorNull));
CFAttributedStringReplaceString(str.get(), CFRangeMake(0, 0), base.get());
const UniChar replacment_char = 0xFFFC;
CFAutoRelease<CFStringRef> replacment_str(CFStringCreateWithCharacters(kCFAllocatorDefault, &replacment_char, 1));
/* Apply font and colour ranges to our string. This is important to make sure
* that we get proper glyph boundaries on style changes. */
int last = 0;
@ -192,12 +189,10 @@ static CTRunDelegateCallbacks _sprite_font_callback = {
CFAttributedStringSetAttribute(str.get(), CFRangeMake(last, i.first - last), kCTForegroundColorAttributeName, color);
CGColorRelease(color);
/* Install a size callback for our special private-use sprite glyphs in case the font does not provide them. */
/* Install a size callback for our special sprite glyphs. */
for (ssize_t c = last; c < i.first; c++) {
if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END && i.second->fc->MapCharToGlyph(buff[c], false) == 0) {
if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END) {
CFAutoRelease<CTRunDelegateRef> del(CTRunDelegateCreate(&_sprite_font_callback, (void *)(size_t)(buff[c] | (i.second->fc->GetSize() << 24))));
/* According to the offical documentation, if a run delegate is used, the char should always be 0xFFFC. */
CFAttributedStringReplaceString(str.get(), CFRangeMake(c, 1), replacment_str.get());
CFAttributedStringSetAttribute(str.get(), CFRangeMake(c, 1), kCTRunDelegateAttributeName, del.get());
}
}
@ -247,8 +242,7 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font
CGGlyph gl[this->glyphs.size()];
CTRunGetGlyphs(run, CFRangeMake(0, 0), gl);
for (size_t i = 0; i < this->glyphs.size(); i++) {
if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END && (gl[i] == 0 || gl[i] == 3)) {
/* A glyph of 0 indidicates not found, while apparently 3 is what char 0xFFFC maps to. */
if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END) {
this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]);
this->positions[i * 2 + 0] = pts[i].x;
this->positions[i * 2 + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre

View File

@ -282,10 +282,14 @@ void Win32FontCache::ClearFontCache()
return new_glyph.sprite;
}
/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key)
{
assert(IsPrintable(key));
if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
return this->parent->MapCharToGlyph(key);
}
/* Convert characters outside of the BMP into surrogate pairs. */
WCHAR chars[2];
if (key >= 0x010000U) {
@ -298,8 +302,7 @@ void Win32FontCache::ClearFontCache()
WORD glyphs[2] = { 0, 0 };
GetGlyphIndicesW(this->dc, chars, key >= 0x010000U ? 2 : 1, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
if (glyphs[0] != 0xFFFF) return glyphs[0];
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
return glyphs[0] != 0xFFFF ? glyphs[0] : 0;
}
/* virtual */ const void *Win32FontCache::InternalGetFontTable(uint32_t tag, size_t &length)
@ -317,66 +320,6 @@ void Win32FontCache::ClearFontCache()
}
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
{
wchar_t fontPath[MAX_PATH] = {};
/* See if this is an absolute path. */
if (FileExists(font_name)) {
convert_to_fs(font_name, fontPath, lengthof(fontPath));
} else {
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
convert_to_fs(font_name, fontPath, lengthof(fontPath));
}
}
if (fontPath[0] != 0) {
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
/* Try a nice little undocumented function first for getting the internal font name.
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
static LibraryLoader _gdi32("gdi32.dll");
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
if (GetFontResourceInfo != nullptr) {
/* Try to query an array of LOGFONTs that describe the file. */
DWORD len = 0;
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
LOGFONT *buf = (LOGFONT *)new byte[len];
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
logfont = *buf; // Just use first entry.
}
delete[](byte *)buf;
}
}
/* No dice yet. Use the file name as the font face name, hoping it matches. */
if (logfont.lfFaceName[0] == 0) {
wchar_t fname[_MAX_FNAME];
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
logfont.lfWeight = strcasestr(font_name.c_str(), " bold") != nullptr || strcasestr(font_name.c_str(), "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
}
}
}
return logfont.lfFaceName[0] != 0;
}
static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, const char *font_name)
{
HFONT font = CreateFontIndirect(&logfont);
if (font == nullptr) {
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
return;
}
DeleteObject(font);
new Win32FontCache(fs, logfont, size);
}
/**
* Loads the GDI font.
* If a GDI font description is present, e.g. from the automatic font
@ -401,8 +344,51 @@ void LoadWin32Font(FontSize fs)
logfont = *(const LOGFONT *)settings->os_handle;
} else if (strchr(font_name, '.') != nullptr) {
/* Might be a font file name, try load it. */
if (!TryLoadFontFromFile(settings->font, logfont)) {
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font_name, FontSizeToName(fs));
wchar_t fontPath[MAX_PATH] = {};
/* See if this is an absolute path. */
if (FileExists(settings->font)) {
convert_to_fs(font_name, fontPath, lengthof(fontPath));
} else {
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
convert_to_fs(font_name, fontPath, lengthof(fontPath));
}
}
if (fontPath[0] != 0) {
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
/* Try a nice little undocumented function first for getting the internal font name.
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
static LibraryLoader _gdi32("gdi32.dll");
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
if (GetFontResourceInfo != nullptr) {
/* Try to query an array of LOGFONTs that describe the file. */
DWORD len = 0;
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
LOGFONT *buf = (LOGFONT *)new byte[len];
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
logfont = *buf; // Just use first entry.
}
delete[] (byte *)buf;
}
}
/* No dice yet. Use the file name as the font face name, hoping it matches. */
if (logfont.lfFaceName[0] == 0) {
wchar_t fname[_MAX_FNAME];
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
logfont.lfWeight = strcasestr(font_name, " bold") != nullptr || strcasestr(font_name, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
}
} else {
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font_name, FontSizeToName(fs));
}
}
}
@ -411,25 +397,12 @@ void LoadWin32Font(FontSize fs)
convert_to_fs(font_name, logfont.lfFaceName, lengthof(logfont.lfFaceName));
}
LoadWin32Font(fs, logfont, settings->size, font_name);
}
/**
* Load a TrueType font from a file.
* @param fs The font size to load.
* @param file_name Path to the font file.
* @param size Requested font size.
*/
void LoadWin32Font(FontSize fs, const std::string &file_name, uint size)
{
LOGFONT logfont;
MemSetT(&logfont, 0);
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
if (TryLoadFontFromFile(file_name, logfont)) {
LoadWin32Font(fs, logfont, size, file_name.c_str());
HFONT font = CreateFontIndirect(&logfont);
if (font == nullptr) {
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
return;
}
DeleteObject(font);
new Win32FontCache(fs, logfont, settings->size);
}

View File

@ -35,12 +35,11 @@ public:
Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels);
~Win32FontCache();
void ClearFontCache() override;
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
GlyphID MapCharToGlyph(char32_t key) override;
std::string GetFontName() override { return this->fontname; }
const void *GetOSHandle() override { return &this->logfont; }
};
void LoadWin32Font(FontSize fs);
void LoadWin32Font(FontSize fs, const std::string &file_name, uint size);
#endif /* FONT_WIN32_H */

View File

@ -194,11 +194,9 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b
for (int i = 0; i < range.len; i++) {
if (buff[range.pos + i] >= SCC_SPRITE_START && buff[range.pos + i] <= SCC_SPRITE_END) {
auto pos = range.char_to_glyph[i];
if (range.ft_glyphs[pos] == 0) { // Font doesn't have our special glyph, so remap.
range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]);
range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre
range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]);
}
range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]);
range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre
range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]);
}
}

View File

@ -50,10 +50,6 @@
#include "safeguards.h"
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
# define HAS_TRUETYPE_FONT
#endif
static const StringID _autosave_dropdown[] = {
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF,
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_10_MINUTES,
@ -563,31 +559,6 @@ struct GameOptionsWindow : Window {
break;
}
#ifdef HAS_TRUETYPE_FONT
case WID_GO_GUI_FONT_SPRITE:
_fcsettings.prefer_sprite = !_fcsettings.prefer_sprite;
this->SetWidgetLoweredState(WID_GO_GUI_FONT_SPRITE, _fcsettings.prefer_sprite);
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
this->SetDirty();
InitFontCache(false);
InitFontCache(true);
ClearFontCache();
SetupWidgetDimensions();
ReInitAllWindows(true);
break;
case WID_GO_GUI_FONT_AA:
_fcsettings.global_aa = !_fcsettings.global_aa;
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
this->SetDirty();
ClearFontCache();
break;
#endif /* HAS_TRUETYPE_FONT */
case WID_GO_GUI_SCALE:
if (ClickSliderWidget(this->GetWidget<NWidgetBase>(widget)->GetCurrentRect(), pt, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE, this->gui_scale)) {
if (!_ctrl_pressed) this->gui_scale = ((this->gui_scale + 12) / 25) * 25;
@ -779,11 +750,6 @@ struct GameOptionsWindow : Window {
this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, _gui_scale_cfg == -1);
this->SetWidgetLoweredState(WID_GO_GUI_SCALE_BEVEL_BUTTON, _settings_client.gui.scale_bevels);
#ifdef HAS_TRUETYPE_FONT
this->SetWidgetLoweredState(WID_GO_GUI_FONT_SPRITE, _fcsettings.prefer_sprite);
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
#endif /* HAS_TRUETYPE_FONT */
this->SetWidgetDisabledState(WID_GO_BASE_GRF_DROPDOWN, _game_mode != GM_MENU);
this->SetWidgetDisabledState(WID_GO_BASE_SFX_DROPDOWN, _game_mode != GM_MENU);
@ -857,16 +823,6 @@ static const NWidgetPart _nested_game_options_widgets[] = {
NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_SCALE_BEVELS, STR_NULL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_BEVEL_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP),
EndContainer(),
#ifdef HAS_TRUETYPE_FONT
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0),
NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_FONT_SPRITE, STR_NULL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_FONT_SPRITE), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0),
NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_FONT_AA, STR_NULL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_FONT_AA), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP),
EndContainer(),
#endif /* HAS_TRUETYPE_FONT */
EndContainer(),
EndContainer(),

View File

@ -258,18 +258,6 @@ name = ""mono_aa""
var = _fcsettings.mono.aa
def = false
[SDTG_BOOL]
ifdef = HAS_TRUETYPE_FONT
name = ""global_aa""
var = _fcsettings.global_aa
def = true
[SDTG_BOOL]
ifdef = HAS_TRUETYPE_FONT
name = ""prefer_sprite_font""
var = _fcsettings.prefer_sprite
def = false
[SDTG_VAR]
name = ""sprite_cache_size_px""
type = SLE_UINT

View File

@ -29,7 +29,7 @@ public:
const Sprite *GetGlyph(GlyphID) override { return nullptr; }
uint GetGlyphWidth(GlyphID) override { return this->height / 2; }
bool GetDrawGlyphShadow() override { return false; }
GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { return key; }
GlyphID MapCharToGlyph(char32_t key) override { return key; }
const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; }
std::string GetFontName() override { return "mock"; }
bool IsBuiltInFont() override { return true; }

View File

@ -59,15 +59,13 @@ static void FindResolutions()
{
_resolutions.clear();
for (int display = 0; display < SDL_GetNumVideoDisplays(); display++) {
for (int i = 0; i < SDL_GetNumDisplayModes(display); i++) {
SDL_DisplayMode mode;
SDL_GetDisplayMode(display, i, &mode);
for (int i = 0; i < SDL_GetNumDisplayModes(0); i++) {
SDL_DisplayMode mode;
SDL_GetDisplayMode(0, i, &mode);
if (mode.w < 640 || mode.h < 480) continue;
if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(mode.w, mode.h)) != _resolutions.end()) continue;
_resolutions.emplace_back(mode.w, mode.h);
}
if (mode.w < 640 || mode.h < 480) continue;
if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(mode.w, mode.h)) != _resolutions.end()) continue;
_resolutions.emplace_back(mode.w, mode.h);
}
/* We have found no resolutions, show the default list */
@ -665,7 +663,7 @@ bool VideoDriver_SDL_Base::ToggleFullscreen(bool fullscreen)
if (fullscreen) {
/* Find fullscreen window size */
SDL_DisplayMode dm;
if (SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(this->sdl_window), &dm) < 0) {
if (SDL_GetCurrentDisplayMode(0, &dm) < 0) {
Debug(driver, 0, "SDL_GetCurrentDisplayMode() failed: {}", SDL_GetError());
} else {
SDL_SetWindowSize(this->sdl_window, dm.w, dm.h);

View File

@ -25,8 +25,6 @@ enum GameOptionsWidgets : WidgetID {
WID_GO_GUI_SCALE, ///< GUI Scale slider.
WID_GO_GUI_SCALE_AUTO, ///< Autodetect GUI scale button.
WID_GO_GUI_SCALE_BEVEL_BUTTON, ///< Toggle for chunky bevels.
WID_GO_GUI_FONT_SPRITE, ///< Toggle whether to prefer the sprite font over TTF fonts.
WID_GO_GUI_FONT_AA, ///< Toggle whether to anti-alias fonts.
WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF.
WID_GO_BASE_GRF_PARAMETERS, ///< Base GRF parameters.
WID_GO_BASE_GRF_OPEN_URL, ///< Open base GRF URL.