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 6ab0a30fe6..09f9ce2c8c 100644
--- a/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GlobalLanguage.cpp
@@ -52,16 +52,27 @@
//-----------------------------------------------------------------------------
#include "PreRTS.h"
+#include "Common/AddonCompat.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 ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
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 ) },
@@ -70,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) },
@@ -117,6 +128,7 @@ GlobalLanguage::GlobalLanguage()
m_militaryCaptionSpeed = 0;
m_useHardWrap = FALSE;
m_resolutionFontSizeAdjustment = 0.7f;
+ m_resolutionFontSizeMethod = ResolutionFontSizeMethod_Balanced;
m_militaryCaptionDelayMS = 750;
//End Add
}
@@ -191,14 +203,76 @@ void GlobalLanguage::parseFontFileName( INI *ini, void * instance, void *store,
Int GlobalLanguage::adjustFontSize(Int theFontSize)
{
- Real adjustFactor = TheGlobalData->m_xResolution / (Real)DEFAULT_DISPLAY_WIDTH;
- adjustFactor = 1.0f + (adjustFactor-1.0f) * m_resolutionFontSizeAdjustment;
- if (adjustFactor<1.0f) adjustFactor = 1.0f;
- if (adjustFactor>2.0f) adjustFactor = 2.0f;
+ Real adjustFactor;
+
+ switch (m_resolutionFontSizeMethod)
+ {
+ 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;
+ }
+ 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) * 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;
+
+ 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"; ///