From 4c50112d9ef4a933298e501b6daa8e4b5af4d9fa Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 16 Aug 2025 13:37:35 +0200 Subject: [PATCH 1/5] tweak(font): Redesign and fix the font scaling for large resolutions and non 4:3 aspect ratios --- .../Source/GameClient/GlobalLanguage.cpp | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp index 9ee55242c90..972f9d0863d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp @@ -57,6 +57,7 @@ #include "Common/FileSystem.h" #include "Common/UserPreferences.h" +#include "GameClient/Display.h" #include "GameClient/GlobalLanguage.h" //----------------------------------------------------------------------------- @@ -195,10 +196,34 @@ float GlobalLanguage::getResolutionFontSizeAdjustment( void ) const Int GlobalLanguage::adjustFontSize(Int theFontSize) { - Real adjustFactor = TheGlobalData->m_xResolution / (Real)DEFAULT_DISPLAY_WIDTH; + // TheSuperHackers @tweak xezon 16/08/2025 The size adjustment now also weighs in + // the display height for a balanced rescale on non 4:3 resolutions. + // The aspect ratio scaling is clamped between 1 and 2 to avoid oversizing. + // The scaler no longer clamps at max 2, which makes it work properly for + // 4k Resolutions and beyond. + + Real w = TheDisplay->getWidth(); + Real h = TheDisplay->getHeight(); + const Real aspect = w / h; + Real wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + Real hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; + + if (aspect > 2.0f) + { + // Recompute width at aspect=2 + w = 2.0f * h; + wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + } + else if (aspect < 1.0f) + { + // Recompute height at aspect=1 + h = 1.0f * w; + hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; + } + + Real adjustFactor = (wScale + hScale) * 0.5f; adjustFactor = 1.0f + (adjustFactor-1.0f) * getResolutionFontSizeAdjustment(); - if (adjustFactor<1.0f) adjustFactor = 1.0f; - if (adjustFactor>2.0f) adjustFactor = 2.0f; + if (adjustFactor < 1.0f) adjustFactor = 1.0f; Int pointSize = REAL_TO_INT_FLOOR(theFontSize*adjustFactor); return pointSize; } From f6eea9728e603f25b40d1e6e3a201cab2d31d352 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Tue, 19 Aug 2025 22:52:43 +0200 Subject: [PATCH 2/5] Implement multiple resolution font size methods --- Core/GameEngine/CMakeLists.txt | 2 + Core/GameEngine/Include/Common/AddonCompat.h | 25 +++++ Core/GameEngine/Source/Common/AddonCompat.cpp | 36 +++++++ .../Include/GameClient/GlobalLanguage.h | 15 ++- .../GameEngine/Source/Common/GameEngine.cpp | 1 + .../GameEngine/Source/Common/GlobalData.cpp | 17 ++-- .../Source/GameClient/GlobalLanguage.cpp | 96 ++++++++++++++----- 7 files changed, 154 insertions(+), 38 deletions(-) create mode 100644 Core/GameEngine/Include/Common/AddonCompat.h create mode 100644 Core/GameEngine/Source/Common/AddonCompat.cpp diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 0a58dfc4315..81ca007c376 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -1,6 +1,7 @@ set(GAMEENGINE_SRC # Include/Common/AcademyStats.h # Include/Common/ActionManager.h + Include/Common/AddonCompat.h Include/Common/ArchiveFile.h Include/Common/ArchiveFileSystem.h Include/Common/AsciiString.h @@ -554,6 +555,7 @@ set(GAMEENGINE_SRC # Include/GameNetwork/WOLBrowser/FEBDispatch.h # Include/GameNetwork/WOLBrowser/WebBrowser.h # Include/Precompiled/PreRTS.h + Source/Common/AddonCompat.cpp Source/Common/Audio/AudioEventRTS.cpp Source/Common/Audio/AudioRequest.cpp Source/Common/Audio/DynamicAudioEventInfo.cpp diff --git a/Core/GameEngine/Include/Common/AddonCompat.h b/Core/GameEngine/Include/Common/AddonCompat.h new file mode 100644 index 00000000000..7b8bc2c9e97 --- /dev/null +++ b/Core/GameEngine/Include/Common/AddonCompat.h @@ -0,0 +1,25 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program 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, either version 3 of the License, or +** (at your option) any later version. +** +** This program 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 this program. If not, see . +*/ + +#pragma once + +namespace addon +{ +extern Bool HasFullviewportDat(); + +} // namespace addon diff --git a/Core/GameEngine/Source/Common/AddonCompat.cpp b/Core/GameEngine/Source/Common/AddonCompat.cpp new file mode 100644 index 00000000000..6d88feb47d6 --- /dev/null +++ b/Core/GameEngine/Source/Common/AddonCompat.cpp @@ -0,0 +1,36 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program 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, either version 3 of the License, or +** (at your option) any later version. +** +** This program 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 this program. If not, see . +*/ + +#include "PreRTS.h" + +#include "Common/AddonCompat.h" +#include "Common/FileSystem.h" + +namespace addon +{ +Bool HasFullviewportDat() +{ + Char value = '0'; + if (File* file = TheFileSystem->openFile("GenTool/fullviewport.dat", File::READ | File::BINARY)) + { + file->read(&value, 1); + } + return value != '0'; +} + +} // namespace addon diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h index aa9aa794a2f..77aaecfbedd 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h @@ -65,6 +65,15 @@ class AsciiString; //----------------------------------------------------------------------------- class GlobalLanguage : public SubsystemInterface { +public: + + enum ResolutionFontSizeMethod + { + ResolutionFontSizeMethod_Classic, // Uses the original scaling method. Scales poorly on wide screens and large resolutions. + ResolutionFontSizeMethod_Strict, // Uses a strict scaling method. Width and height are strictly bounded on upscales. Works well for accurate UI layouts and with large resolutions. + ResolutionFontSizeMethod_Balanced, // Uses a balanced scaling method. Width and height are evenly weighted for upscales. Works well for the original Game UI and with large resolutions. + }; + public: GlobalLanguage(); @@ -96,15 +105,15 @@ class GlobalLanguage : public SubsystemInterface FontDesc m_creditsTitleFont; FontDesc m_creditsPositionFont; FontDesc m_creditsNormalFont; - Real m_resolutionFontSizeAdjustment; Real m_userResolutionFontSizeAdjustment; - - //UnicodeString m_unicodeFontNameUStr; + ResolutionFontSizeMethod m_resolutionFontSizeMethod; float getResolutionFontSizeAdjustment() const; Int adjustFontSize(Int theFontSize); // Adjusts font size for resolution. jba. + void parseCustomDefinition(); + typedef std::list StringList; // Used for our font file names that we want to load typedef StringList::iterator StringListIt; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index 2b6bcad36d1..7c7418a6a52 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -520,6 +520,7 @@ void GameEngine::init() initSubsystem(TheTerrainTypes,"TheTerrainTypes", MSGNEW("GameEngineSubsystem") TerrainTypeCollection(), &xferCRC, "Data\\INI\\Default\\Terrain", "Data\\INI\\Terrain"); initSubsystem(TheTerrainRoads,"TheTerrainRoads", MSGNEW("GameEngineSubsystem") TerrainRoadCollection(), &xferCRC, "Data\\INI\\Default\\Roads", "Data\\INI\\Roads"); initSubsystem(TheGlobalLanguageData,"TheGlobalLanguageData",MSGNEW("GameEngineSubsystem") GlobalLanguage, NULL); // must be before the game text + TheGlobalLanguageData->parseCustomDefinition(); initSubsystem(TheCDManager,"TheCDManager", CreateCDManager(), NULL); #ifdef DUMP_PERF_STATS/////////////////////////////////////////////////////////////////////////// GetPrecisionTimer(&endTime64);////////////////////////////////////////////////////////////////// diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp index 41bb35cfe38..071c5debeb3 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp @@ -32,12 +32,15 @@ // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine +#include "Common/GlobalData.h" + #define DEFINE_TERRAIN_LOD_NAMES #define DEFINE_TIME_OF_DAY_NAMES #define DEFINE_WEATHER_NAMES #define DEFINE_BODYDAMAGETYPE_NAMES #define DEFINE_PANNING_NAMES +#include "Common/AddonCompat.h" #include "Common/crc.h" #include "Common/file.h" #include "Common/FileSystem.h" @@ -1246,18 +1249,10 @@ void GlobalData::parseGameDataDefinition( INI* ini ) void GlobalData::parseCustomDefinition() { + if (addon::HasFullviewportDat()) { - // TheSuperHackers @feature xezon 03/08/2025 Force full viewport for 'Control Bar Pro' Addons like GenTool did it. - File* file = TheFileSystem->openFile("GenTool/fullviewport.dat", File::READ | File::BINARY); - if (file != NULL) - { - Char value = '0'; - file->read(&value, 1); - if (value != '0') - { - m_viewportHeightScale = 1.0f; - } - } + // TheSuperHackers @tweak xezon 03/08/2025 Force full viewport for 'Control Bar Pro' Addons like GenTool did it. + m_viewportHeightScale = 1.0f; } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp index 972f9d0863d..f81ab13bbd2 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp @@ -52,6 +52,7 @@ //----------------------------------------------------------------------------- #include "PreRTS.h" +#include "Common/AddonCompat.h" #include "Common/INI.h" #include "Common/Registry.h" #include "Common/FileSystem.h" @@ -65,6 +66,14 @@ //----------------------------------------------------------------------------- GlobalLanguage *TheGlobalLanguageData = NULL; ///< The global language singalton +static const LookupListRec ResolutionFontSizeMethodNames[] = +{ + { "CLASSIC", GlobalLanguage::ResolutionFontSizeMethod_Classic }, + { "STRICT", GlobalLanguage::ResolutionFontSizeMethod_Strict }, + { "BALANCED", GlobalLanguage::ResolutionFontSizeMethod_Balanced }, + { NULL, 0 } +}; + static const FieldParse TheGlobalLanguageDataFieldParseTable[] = { { "UnicodeFontName", INI::parseAsciiString,NULL, offsetof( GlobalLanguage, m_unicodeFontName ) }, @@ -73,7 +82,7 @@ static const FieldParse TheGlobalLanguageDataFieldParseTable[] = { "MilitaryCaptionSpeed", INI::parseInt, NULL, offsetof( GlobalLanguage, m_militaryCaptionSpeed ) }, { "UseHardWordWrap", INI::parseBool, NULL, offsetof( GlobalLanguage, m_useHardWrap) }, { "ResolutionFontAdjustment", INI::parseReal, NULL, offsetof( GlobalLanguage, m_resolutionFontSizeAdjustment) }, - + { "ResolutionFontSizeMethod", INI::parseLookupList, ResolutionFontSizeMethodNames, offsetof( GlobalLanguage, m_resolutionFontSizeMethod) }, { "CopyrightFont", GlobalLanguage::parseFontDesc, NULL, offsetof( GlobalLanguage, m_copyrightFont ) }, { "MessageFont", GlobalLanguage::parseFontDesc, NULL, offsetof( GlobalLanguage, m_messageFont) }, { "MilitaryCaptionTitleFont", GlobalLanguage::parseFontDesc, NULL, offsetof( GlobalLanguage, m_militaryCaptionTitleFont) }, @@ -120,6 +129,7 @@ GlobalLanguage::GlobalLanguage() m_militaryCaptionSpeed = 0; m_useHardWrap = FALSE; m_resolutionFontSizeAdjustment = 0.7f; + m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Balanced; m_militaryCaptionDelayMS = 750; //End Add @@ -196,38 +206,76 @@ float GlobalLanguage::getResolutionFontSizeAdjustment( void ) const Int GlobalLanguage::adjustFontSize(Int theFontSize) { - // TheSuperHackers @tweak xezon 16/08/2025 The size adjustment now also weighs in - // the display height for a balanced rescale on non 4:3 resolutions. - // The aspect ratio scaling is clamped between 1 and 2 to avoid oversizing. - // The scaler no longer clamps at max 2, which makes it work properly for - // 4k Resolutions and beyond. - - Real w = TheDisplay->getWidth(); - Real h = TheDisplay->getHeight(); - const Real aspect = w / h; - Real wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; - Real hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; - - if (aspect > 2.0f) + Real adjustFactor; + + switch (m_resolutionFontSizeMethod) { - // Recompute width at aspect=2 - w = 2.0f * h; - wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + default: + case ResolutionFontSizeMethod_Classic: + { + // TheSuperHackers @info The original font scaling for this game. + // Can be useful for not breaking legacy Addons and Mods but scales poorly. + adjustFactor = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + if (adjustFactor > 2.0f) + adjustFactor = 2.0f; + break; } - else if (aspect < 1.0f) + case ResolutionFontSizeMethod_Strict: { - // Recompute height at aspect=1 - h = 1.0f * w; - hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; + // TheSuperHackers @feature The strict method scales fonts based on the smallest screen + // dimension so they scale independent of aspect ratio. + const Real wScale = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; + const Real hScale = TheDisplay->getHeight() / (Real)DEFAULT_DISPLAY_HEIGHT; + adjustFactor = min(wScale, hScale); + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + break; } + case ResolutionFontSizeMethod_Balanced: + { + // TheSuperHackers @feature The balanced method evenly weighs the display width and height + // for a balanced rescale on non 4:3 resolutions. The aspect ratio scaling is clamped + // between 1 and 2 to avoid oversizing. + Real w = TheDisplay->getWidth(); + Real h = TheDisplay->getHeight(); + const Real aspect = w / h; + Real wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + Real hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; - Real adjustFactor = (wScale + hScale) * 0.5f; - adjustFactor = 1.0f + (adjustFactor-1.0f) * getResolutionFontSizeAdjustment(); - if (adjustFactor < 1.0f) adjustFactor = 1.0f; + if (aspect > 2.0f) + { + // Recompute width at aspect=2 + w = 2.0f * h; + wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + } + else if (aspect < 1.0f) + { + // Recompute height at aspect=1 + h = 1.0f * w; + hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; + } + adjustFactor = (wScale + hScale) * 0.5f; + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + break; + } + } + + if (adjustFactor < 1.0f) + adjustFactor = 1.0f; Int pointSize = REAL_TO_INT_FLOOR(theFontSize*adjustFactor); return pointSize; } +void GlobalLanguage::parseCustomDefinition() +{ + if (addon::HasFullviewportDat()) + { + // TheSuperHackers @tweak xezon 19/08/2025 Force the classic font size adjustment for the old + // 'Control Bar Pro' Addons because they use manual font upscaling in higher resolution packages. + m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Classic; + } +} + FontDesc::FontDesc(void) { name = "Arial Unicode MS"; /// Date: Sun, 9 Nov 2025 11:43:08 +0100 Subject: [PATCH 3/5] Add new default font scaling method ResolutionFontSizeMethod_ClassicNoCeiling --- .../Include/GameClient/GlobalLanguage.h | 3 +++ .../Source/GameClient/GlobalLanguage.cpp | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h index 77aaecfbedd..d69b73eda4d 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h @@ -70,8 +70,11 @@ class GlobalLanguage : public SubsystemInterface enum ResolutionFontSizeMethod { ResolutionFontSizeMethod_Classic, // Uses the original scaling method. Scales poorly on wide screens and large resolutions. + ResolutionFontSizeMethod_ClassicNoCeiling, // Uses the original scaling method, but without ceiling. Works ok for the original Game UI and with large resolutions. Scales poorly on very wide screens. ResolutionFontSizeMethod_Strict, // Uses a strict scaling method. Width and height are strictly bounded on upscales. Works well for accurate UI layouts and with large resolutions. ResolutionFontSizeMethod_Balanced, // Uses a balanced scaling method. Width and height are evenly weighted for upscales. Works well for the original Game UI and with large resolutions. + + ResolutionFontSizeMethod_Default = ResolutionFontSizeMethod_ClassicNoCeiling, }; public: diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp index f81ab13bbd2..17a2463e451 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp @@ -64,11 +64,12 @@ //----------------------------------------------------------------------------- // DEFINES //////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- -GlobalLanguage *TheGlobalLanguageData = NULL; ///< The global language singalton +GlobalLanguage *TheGlobalLanguageData = NULL; ///< The global language singleton static const LookupListRec ResolutionFontSizeMethodNames[] = { { "CLASSIC", GlobalLanguage::ResolutionFontSizeMethod_Classic }, + { "CLASSIC_NO_CEILING", GlobalLanguage::ResolutionFontSizeMethod_ClassicNoCeiling }, { "STRICT", GlobalLanguage::ResolutionFontSizeMethod_Strict }, { "BALANCED", GlobalLanguage::ResolutionFontSizeMethod_Balanced }, { NULL, 0 } @@ -129,7 +130,7 @@ GlobalLanguage::GlobalLanguage() m_militaryCaptionSpeed = 0; m_useHardWrap = FALSE; m_resolutionFontSizeAdjustment = 0.7f; - m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Balanced; + m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Default; m_militaryCaptionDelayMS = 750; //End Add @@ -206,6 +207,8 @@ float GlobalLanguage::getResolutionFontSizeAdjustment( void ) const Int GlobalLanguage::adjustFontSize(Int theFontSize) { + // TheSuperHackers @todo This function is called very often. + // Therefore cache the adjustFactor on resolution change to not recompute it on every call. Real adjustFactor; switch (m_resolutionFontSizeMethod) @@ -214,13 +217,21 @@ Int GlobalLanguage::adjustFontSize(Int theFontSize) case ResolutionFontSizeMethod_Classic: { // TheSuperHackers @info The original font scaling for this game. - // Can be useful for not breaking legacy Addons and Mods but scales poorly. + // Useful for not breaking legacy Addons and Mods. Scales poorly with large resolutions. adjustFactor = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); if (adjustFactor > 2.0f) adjustFactor = 2.0f; break; } + case ResolutionFontSizeMethod_ClassicNoCeiling: + { + // TheSuperHackers @feature The original font scaling, but without ceiling. + // Useful for not changing the original look of the game. Scales alright with large resolutions. + adjustFactor = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + break; + } case ResolutionFontSizeMethod_Strict: { // TheSuperHackers @feature The strict method scales fonts based on the smallest screen From 9ba0c4564ac7be782b7ca45411a1a00e31e0c128 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 10 Nov 2025 18:54:22 +0100 Subject: [PATCH 4/5] Tweak balanced scaling method limits --- .../Source/GameClient/GlobalLanguage.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp index 17a2463e451..2b279e0c56e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp @@ -245,24 +245,26 @@ Int GlobalLanguage::adjustFontSize(Int theFontSize) case ResolutionFontSizeMethod_Balanced: { // TheSuperHackers @feature The balanced method evenly weighs the display width and height - // for a balanced rescale on non 4:3 resolutions. The aspect ratio scaling is clamped - // between 1 and 2 to avoid oversizing. + // for a balanced rescale on non 4:3 resolutions. The aspect ratio scaling is clamped to + // prevent oversizing. + constexpr const Real maxAspect = 1.8f; + constexpr const Real minAspect = 1.0f; Real w = TheDisplay->getWidth(); Real h = TheDisplay->getHeight(); const Real aspect = w / h; Real wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; Real hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; - if (aspect > 2.0f) + if (aspect > maxAspect) { - // Recompute width at aspect=2 - w = 2.0f * h; + // Recompute width at max aspect + w = maxAspect * h; wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; } - else if (aspect < 1.0f) + else if (aspect < minAspect) { - // Recompute height at aspect=1 - h = 1.0f * w; + // Recompute height at min aspect + h = minAspect * w; hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; } adjustFactor = (wScale + hScale) * 0.5f; From 6baf08fe0cfea91041bd3db93e68b599b82be6da Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 10 Nov 2025 19:23:38 +0100 Subject: [PATCH 5/5] Replicate in Generals --- .../Include/GameClient/GlobalLanguage.h | 18 +++- .../GameEngine/Source/Common/GameEngine.cpp | 1 + .../GameEngine/Source/Common/GlobalData.cpp | 17 ++-- .../Source/GameClient/GlobalLanguage.cpp | 98 +++++++++++++++++-- 4 files changed, 114 insertions(+), 20 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/GlobalLanguage.h b/Generals/Code/GameEngine/Include/GameClient/GlobalLanguage.h index 531df385741..9ceb7abe0fa 100644 --- a/Generals/Code/GameEngine/Include/GameClient/GlobalLanguage.h +++ b/Generals/Code/GameEngine/Include/GameClient/GlobalLanguage.h @@ -65,6 +65,18 @@ class AsciiString; //----------------------------------------------------------------------------- class GlobalLanguage : public SubsystemInterface { +public: + + enum ResolutionFontSizeMethod + { + ResolutionFontSizeMethod_Classic, // Uses the original scaling method. Scales poorly on wide screens and large resolutions. + ResolutionFontSizeMethod_ClassicNoCeiling, // Uses the original scaling method, but without ceiling. Works ok for the original Game UI and with large resolutions. Scales poorly on very wide screens. + ResolutionFontSizeMethod_Strict, // Uses a strict scaling method. Width and height are strictly bounded on upscales. Works well for accurate UI layouts and with large resolutions. + ResolutionFontSizeMethod_Balanced, // Uses a balanced scaling method. Width and height are evenly weighted for upscales. Works well for the original Game UI and with large resolutions. + + ResolutionFontSizeMethod_Default = ResolutionFontSizeMethod_ClassicNoCeiling, + }; + public: GlobalLanguage(); @@ -95,15 +107,15 @@ class GlobalLanguage : public SubsystemInterface FontDesc m_creditsTitleFont; FontDesc m_creditsPositionFont; FontDesc m_creditsNormalFont; - Real m_resolutionFontSizeAdjustment; Real m_userResolutionFontSizeAdjustment; - - //UnicodeString m_unicodeFontNameUStr; + ResolutionFontSizeMethod m_resolutionFontSizeMethod; float getResolutionFontSizeAdjustment() const; Int adjustFontSize(Int theFontSize); // Adjusts font size for resolution. jba. + void parseCustomDefinition(); + typedef std::list StringList; // Used for our font file names that we want to load typedef StringList::iterator StringListIt; diff --git a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp index 7943cab3292..e4a20be08cc 100644 --- a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp @@ -434,6 +434,7 @@ void GameEngine::init() initSubsystem(TheTerrainTypes,"TheTerrainTypes", MSGNEW("GameEngineSubsystem") TerrainTypeCollection(), &xferCRC, "Data\\INI\\Default\\Terrain", "Data\\INI\\Terrain"); initSubsystem(TheTerrainRoads,"TheTerrainRoads", MSGNEW("GameEngineSubsystem") TerrainRoadCollection(), &xferCRC, "Data\\INI\\Default\\Roads", "Data\\INI\\Roads"); initSubsystem(TheGlobalLanguageData,"TheGlobalLanguageData",MSGNEW("GameEngineSubsystem") GlobalLanguage, NULL); // must be before the game text + TheGlobalLanguageData->parseCustomDefinition(); initSubsystem(TheCDManager,"TheCDManager", CreateCDManager(), NULL); initSubsystem(TheAudio,"TheAudio", TheGlobalData->m_headless ? NEW AudioManagerDummy : createAudioManager(), NULL); if (!TheAudio->isMusicAlreadyLoaded()) diff --git a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp index 9030c358e6e..4b722238773 100644 --- a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp @@ -32,12 +32,15 @@ // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine +#include "Common/GlobalData.h" + #define DEFINE_TERRAIN_LOD_NAMES #define DEFINE_TIME_OF_DAY_NAMES #define DEFINE_WEATHER_NAMES #define DEFINE_BODYDAMAGETYPE_NAMES #define DEFINE_PANNING_NAMES +#include "Common/AddonCompat.h" #include "Common/crc.h" #include "Common/file.h" #include "Common/FileSystem.h" @@ -1218,18 +1221,10 @@ void GlobalData::parseGameDataDefinition( INI* ini ) void GlobalData::parseCustomDefinition() { + if (addon::HasFullviewportDat()) { - // TheSuperHackers @feature xezon 03/08/2025 Force full viewport for 'Control Bar Pro' Addons like GenTool did it. - File* file = TheFileSystem->openFile("GenTool/fullviewport.dat", File::READ | File::BINARY); - if (file != NULL) - { - Char value = '0'; - file->read(&value, 1); - if (value != '0') - { - m_viewportHeightScale = 1.0f; - } - } + // TheSuperHackers @tweak xezon 03/08/2025 Force full viewport for 'Control Bar Pro' Addons like GenTool did it. + m_viewportHeightScale = 1.0f; } } diff --git a/Generals/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp b/Generals/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp index 68f47aacb15..d41cae4064b 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp @@ -52,17 +52,28 @@ //----------------------------------------------------------------------------- #include "PreRTS.h" +#include "Common/AddonCompat.h" #include "Common/INI.h" #include "Common/Registry.h" #include "Common/FileSystem.h" #include "Common/UserPreferences.h" +#include "GameClient/Display.h" #include "GameClient/GlobalLanguage.h" //----------------------------------------------------------------------------- // DEFINES //////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- -GlobalLanguage *TheGlobalLanguageData = NULL; ///< The global language singalton +GlobalLanguage *TheGlobalLanguageData = NULL; ///< The global language singleton + +static const LookupListRec ResolutionFontSizeMethodNames[] = +{ + { "CLASSIC", GlobalLanguage::ResolutionFontSizeMethod_Classic }, + { "CLASSIC_NO_CEILING", GlobalLanguage::ResolutionFontSizeMethod_ClassicNoCeiling }, + { "STRICT", GlobalLanguage::ResolutionFontSizeMethod_Strict }, + { "BALANCED", GlobalLanguage::ResolutionFontSizeMethod_Balanced }, + { NULL, 0 } +}; static const FieldParse TheGlobalLanguageDataFieldParseTable[] = { @@ -72,7 +83,7 @@ static const FieldParse TheGlobalLanguageDataFieldParseTable[] = { "MilitaryCaptionSpeed", INI::parseInt, NULL, offsetof( GlobalLanguage, m_militaryCaptionSpeed ) }, { "UseHardWordWrap", INI::parseBool, NULL, offsetof( GlobalLanguage, m_useHardWrap) }, { "ResolutionFontAdjustment", INI::parseReal, NULL, offsetof( GlobalLanguage, m_resolutionFontSizeAdjustment) }, - + { "ResolutionFontSizeMethod", INI::parseLookupList, ResolutionFontSizeMethodNames, offsetof( GlobalLanguage, m_resolutionFontSizeMethod) }, { "CopyrightFont", GlobalLanguage::parseFontDesc, NULL, offsetof( GlobalLanguage, m_copyrightFont ) }, { "MessageFont", GlobalLanguage::parseFontDesc, NULL, offsetof( GlobalLanguage, m_messageFont) }, { "MilitaryCaptionTitleFont", GlobalLanguage::parseFontDesc, NULL, offsetof( GlobalLanguage, m_militaryCaptionTitleFont) }, @@ -118,6 +129,7 @@ GlobalLanguage::GlobalLanguage() m_militaryCaptionSpeed = 0; m_useHardWrap = FALSE; m_resolutionFontSizeAdjustment = 0.7f; + m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Default; //End Add m_userResolutionFontSizeAdjustment = -1.0f; @@ -193,14 +205,88 @@ float GlobalLanguage::getResolutionFontSizeAdjustment( void ) const Int GlobalLanguage::adjustFontSize(Int theFontSize) { - Real adjustFactor = TheGlobalData->m_xResolution / (Real)DEFAULT_DISPLAY_WIDTH; - adjustFactor = 1.0f + (adjustFactor-1.0f) * getResolutionFontSizeAdjustment(); - if (adjustFactor<1.0f) adjustFactor = 1.0f; - if (adjustFactor>2.0f) adjustFactor = 2.0f; + // TheSuperHackers @todo This function is called very often. + // Therefore cache the adjustFactor on resolution change to not recompute it on every call. + Real adjustFactor; + + switch (m_resolutionFontSizeMethod) + { + default: + case ResolutionFontSizeMethod_Classic: + { + // TheSuperHackers @info The original font scaling for this game. + // Useful for not breaking legacy Addons and Mods. Scales poorly with large resolutions. + adjustFactor = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + if (adjustFactor > 2.0f) + adjustFactor = 2.0f; + break; + } + case ResolutionFontSizeMethod_ClassicNoCeiling: + { + // TheSuperHackers @feature The original font scaling, but without ceiling. + // Useful for not changing the original look of the game. Scales alright with large resolutions. + adjustFactor = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + break; + } + case ResolutionFontSizeMethod_Strict: + { + // TheSuperHackers @feature The strict method scales fonts based on the smallest screen + // dimension so they scale independent of aspect ratio. + const Real wScale = TheDisplay->getWidth() / (Real)DEFAULT_DISPLAY_WIDTH; + const Real hScale = TheDisplay->getHeight() / (Real)DEFAULT_DISPLAY_HEIGHT; + adjustFactor = min(wScale, hScale); + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + break; + } + case ResolutionFontSizeMethod_Balanced: + { + // TheSuperHackers @feature The balanced method evenly weighs the display width and height + // for a balanced rescale on non 4:3 resolutions. The aspect ratio scaling is clamped to + // prevent oversizing. + constexpr const Real maxAspect = 1.8f; + constexpr const Real minAspect = 1.0f; + Real w = TheDisplay->getWidth(); + Real h = TheDisplay->getHeight(); + const Real aspect = w / h; + Real wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + Real hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; + + if (aspect > maxAspect) + { + // Recompute width at max aspect + w = maxAspect * h; + wScale = w / (Real)DEFAULT_DISPLAY_WIDTH; + } + else if (aspect < minAspect) + { + // Recompute height at min aspect + h = minAspect * w; + hScale = h / (Real)DEFAULT_DISPLAY_HEIGHT; + } + adjustFactor = (wScale + hScale) * 0.5f; + adjustFactor = 1.0f + (adjustFactor - 1.0f) * getResolutionFontSizeAdjustment(); + break; + } + } + + if (adjustFactor < 1.0f) + adjustFactor = 1.0f; Int pointSize = REAL_TO_INT_FLOOR(theFontSize*adjustFactor); return pointSize; } +void GlobalLanguage::parseCustomDefinition() +{ + if (addon::HasFullviewportDat()) + { + // TheSuperHackers @tweak xezon 19/08/2025 Force the classic font size adjustment for the old + // 'Control Bar Pro' Addons because they use manual font upscaling in higher resolution packages. + m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Classic; + } +} + FontDesc::FontDesc(void) { name = "Arial Unicode MS"; ///