From d3784a4b6866ae27b1441e09851e5dfb185b6bcb 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/2] tweak(font): Redesign and fix the font scaling for large resolutions and non 4:3 aspect ratios --- .../Source/GameClient/GlobalLanguage.cpp | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp index 6ab0a30fe6..bbee23a3ef 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp @@ -52,10 +52,12 @@ //----------------------------------------------------------------------------- #include "PreRTS.h" +#include "Common/FileSystem.h" #include "Common/INI.h" #include "Common/Registry.h" + +#include "GameClient/Display.h" #include "GameClient/GlobalLanguage.h" -#include "Common/FileSystem.h" //----------------------------------------------------------------------------- // DEFINES //////////////////////////////////////////////////////////////////// @@ -191,10 +193,34 @@ void GlobalLanguage::parseFontFileName( INI *ini, void * instance, void *store, 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) * m_resolutionFontSizeAdjustment; - 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 01dc8cbdfb02d82bab844b2b294e076645177f21 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/2] 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 494d544f73..027e201952 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 @@ -552,6 +553,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 0000000000..7b8bc2c9e9 --- /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 0000000000..6d88feb47d --- /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 a8324393c9..fbf91b36db 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GlobalLanguage.h @@ -68,6 +68,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(); @@ -99,13 +108,13 @@ class GlobalLanguage : public SubsystemInterface FontDesc m_creditsTitleFont; FontDesc m_creditsPositionFont; FontDesc m_creditsNormalFont; - Real m_resolutionFontSizeAdjustment; - - //UnicodeString m_unicodeFontNameUStr; + ResolutionFontSizeMethod m_resolutionFontSizeMethod; 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 f15842701d..65526bf84d 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -495,6 +495,7 @@ void GameEngine::init() initSubsystem(TheTerrainTypes,"TheTerrainTypes", MSGNEW("GameEngineSubsystem") TerrainTypeCollection(), &xferCRC, "Data\\INI\\Default\\Terrain.ini", "Data\\INI\\Terrain.ini"); initSubsystem(TheTerrainRoads,"TheTerrainRoads", MSGNEW("GameEngineSubsystem") TerrainRoadCollection(), &xferCRC, "Data\\INI\\Default\\Roads.ini", "Data\\INI\\Roads.ini"); 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 be4b8962e2..5f86ccb8e4 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" @@ -1226,18 +1229,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 bbee23a3ef..09f9ce2c8c 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/FileSystem.h" #include "Common/INI.h" #include "Common/Registry.h" @@ -64,6 +65,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 ) }, @@ -72,7 +81,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) }, @@ -119,6 +128,7 @@ GlobalLanguage::GlobalLanguage() m_militaryCaptionSpeed = 0; m_useHardWrap = FALSE; m_resolutionFontSizeAdjustment = 0.7f; + m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Balanced; m_militaryCaptionDelayMS = 750; //End Add } @@ -193,38 +203,76 @@ void GlobalLanguage::parseFontFileName( INI *ini, void * instance, void *store, 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) * m_resolutionFontSizeAdjustment; + 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) * m_resolutionFontSizeAdjustment; + 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) * m_resolutionFontSizeAdjustment; - 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) * m_resolutionFontSizeAdjustment; + 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"; ///