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"; ///