Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1e7ee6a
Add stb library dependency via FetchContent
bobtista Nov 2, 2025
3126d6f
Add MSG_META_TAKE_SCREENSHOT_COMPRESSED message and F11 keybinding
bobtista Nov 2, 2025
ab2d333
Implement threaded JPEG screenshot for GeneralsMD
bobtista Nov 2, 2025
53fd0d5
Use Win32 CreateThread for VC6 compatibility and add GUIEditDisplay stub
bobtista Nov 3, 2025
00ff872
Move screenshot logic to Core to eliminate code duplication
bobtista Nov 3, 2025
734385f
Change F12 to JPEG and add CTRL+F12 for PNG screenshots
bobtista Nov 3, 2025
285c3e4
Remove old BMP screenshot code
bobtista Nov 3, 2025
8dac55f
Add JPEGQuality option to Options.ini (default 80)
bobtista Nov 3, 2025
148b260
Remove trailing whitespace from empty lines
bobtista Nov 22, 2025
c509412
Fix copyright headers: Change Electronic Arts Inc. to TheSuperHackers
bobtista Nov 22, 2025
de4929c
Add file headers to W3DScreenshot.cpp files
bobtista Nov 22, 2025
269af80
Rename MSG_META_TAKE_SCREENSHOT_JPEG to MSG_META_TAKE_SCREENSHOT_PNG
bobtista Nov 22, 2025
ef67a08
fix(screenshot): Fix W3DScreenshot.cpp references in CMakeLists after…
bobtista Dec 3, 2025
82f858a
fix(screenshot): Add missing W3DScreenshot.h include for ScreenshotFo…
bobtista Dec 3, 2025
a888657
fix(screenshot): Use full include path for W3DScreenshot.h from Core
bobtista Dec 3, 2025
d1ed4f1
fix(screenshot): Remove W3DScreenshot.cpp from separate compilation s…
bobtista Dec 3, 2025
ea0abcc
refactor(screenshot): Consolidate stb_image_write_impl.cpp to Core
bobtista Dec 3, 2025
7d700d7
docs(unify): Document stb_image_write_impl.cpp unification in script
bobtista Dec 3, 2025
a4de747
fix(screenshot): Restore DESTROY_MESSAGE, fix quality default, NULL t…
bobtista Feb 16, 2026
ce03627
fix(screenshot): Replicate screenshot fixes to Generals
bobtista Feb 16, 2026
e62f2c2
refactor(screenshot): Compile W3DScreenshot.cpp as separate translati…
bobtista Feb 16, 2026
30b405d
refactor(screenshot): Replicate separate compilation fix to Generals
bobtista Feb 16, 2026
b50793c
fix(screenshot): Initialize m_jpegQuality in constructor and remove e…
bobtista Feb 16, 2026
c339280
fix(screenshot): Replicate m_jpegQuality init and CMake cleanup to Ge…
bobtista Feb 16, 2026
20a9eb2
Only show screen capture message when screenshot thread is successful…
bobtista Feb 24, 2026
b709c32
Remove dead CreateBMPFile function replaced by compressed screenshot
bobtista Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ endif()
include(cmake/config.cmake)
include(cmake/gamespy.cmake)
include(cmake/lzhl.cmake)
include(cmake/stb.cmake)

if (IS_VS6_BUILD)
# The original max sdk does not compile against a modern compiler.
Expand Down
1 change: 1 addition & 0 deletions Core/GameEngine/Include/Common/OptionPreferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class OptionPreferences : public UserPreferences
Bool getAlternateMouseModeEnabled();
Bool getRetaliationModeEnabled();
Bool getDoubleClickAttackMoveEnabled();
Int getJPEGQuality();
Real getScrollFactor();
Bool getDrawScrollAnchor();
Bool getMoveScrollAnchor();
Expand Down
12 changes: 12 additions & 0 deletions Core/GameEngine/Source/Common/OptionPreferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ Bool OptionPreferences::getDoubleClickAttackMoveEnabled()
return FALSE;
}

Int OptionPreferences::getJPEGQuality()
{
OptionPreferences::const_iterator it = find("JPEGQuality");
if (it == end())
return 80;

Int quality = atoi(it->second.str());
if (quality < 1) quality = 1;
if (quality > 100) quality = 100;
Comment on lines +201 to +203

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clamp

return quality;
}

Real OptionPreferences::getScrollFactor()
{
OptionPreferences::const_iterator it = find("ScrollFactor");
Expand Down
4 changes: 4 additions & 0 deletions Core/GameEngineDevice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ set(GAMEENGINEDEVICE_SRC
Include/W3DDevice/GameClient/W3DTreeBuffer.h
Include/W3DDevice/GameClient/W3DVideoBuffer.h
Include/W3DDevice/GameClient/W3DView.h
Include/W3DDevice/GameClient/W3DScreenshot.h
# Include/W3DDevice/GameClient/W3DVolumetricShadow.h
Include/W3DDevice/GameClient/W3DWater.h
Include/W3DDevice/GameClient/W3DWaterTracks.h
Expand Down Expand Up @@ -173,6 +174,8 @@ set(GAMEENGINEDEVICE_SRC
Source/W3DDevice/GameClient/W3DTreeBuffer.cpp
Source/W3DDevice/GameClient/W3DVideoBuffer.cpp
Source/W3DDevice/GameClient/W3DView.cpp
# Source/W3DDevice/GameClient/W3DScreenshot.cpp
Source/W3DDevice/GameClient/stb_image_write_impl.cpp
# Source/W3DDevice/GameClient/W3dWaypointBuffer.cpp
# Source/W3DDevice/GameClient/W3DWebBrowser.cpp
Source/W3DDevice/GameClient/Water/W3DWater.cpp
Expand Down Expand Up @@ -218,6 +221,7 @@ target_include_directories(corei_gameenginedevice_public INTERFACE
target_link_libraries(corei_gameenginedevice_private INTERFACE
corei_always
corei_main
stb
)

target_link_libraries(corei_gameenginedevice_public INTERFACE
Expand Down
24 changes: 24 additions & 0 deletions Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScreenshot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "GameClient/Display.h"

void W3D_TakeCompressedScreenshot(ScreenshotFormat format, int quality = 0);

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
** Command & Conquer Generals(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 <http://www.gnu.org/licenses/>.
*/

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>

1 change: 1 addition & 0 deletions Generals/Code/GameEngine/Include/Common/GlobalData.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class GlobalData : public SubsystemInterface
Bool m_clientRetaliationModeEnabled;
Bool m_doubleClickAttackMove;
Bool m_rightMouseAlwaysScrolls;
Int m_jpegQuality;
Bool m_useWaterPlane;
Bool m_useCloudPlane;
Bool m_useShadowVolumes;
Expand Down
3 changes: 2 additions & 1 deletion Generals/Code/GameEngine/Include/Common/MessageStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ class GameMessage : public MemoryPoolObject
MSG_META_BEGIN_PREFER_SELECTION, ///< The Shift key has been depressed alone
MSG_META_END_PREFER_SELECTION, ///< The Shift key has been released.

MSG_META_TAKE_SCREENSHOT, ///< take screenshot
MSG_META_TAKE_SCREENSHOT, ///< take JPEG screenshot (F12)
MSG_META_TAKE_SCREENSHOT_PNG, ///< take PNG screenshot (CTRL+F12, lossless)
MSG_META_ALL_CHEER, ///< Yay! :)
MSG_META_TOGGLE_ATTACKMOVE, ///< enter attack-move mode

Expand Down
8 changes: 7 additions & 1 deletion Generals/Code/GameEngine/Include/GameClient/Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
#include "GameClient/GameFont.h"
#include "GameClient/View.h"

enum ScreenshotFormat
{
SCREENSHOT_JPEG,
SCREENSHOT_PNG
};

struct ShroudLevel
{
Short m_currentShroud; ///< A Value of 1 means shrouded. 0 is not. Negative is the count of people looking.
Expand Down Expand Up @@ -166,7 +172,7 @@ class Display : public SubsystemInterface
virtual void preloadModelAssets( AsciiString model ) = 0; ///< preload model asset
virtual void preloadTextureAssets( AsciiString texture ) = 0; ///< preload texture asset

virtual void takeScreenShot() = 0; ///< saves screenshot to a file
virtual void takeScreenShot(ScreenshotFormat format) = 0; ///< saves screenshot in specified format
virtual void toggleMovieCapture() = 0; ///< starts saving frames to an avi or frame sequence
virtual void toggleLetterBox() = 0; ///< enabled letter-boxed display
virtual void enableLetterBox(Bool enable) = 0; ///< forces letter-boxed display on/off
Expand Down
2 changes: 2 additions & 0 deletions Generals/Code/GameEngine/Source/Common/GlobalData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ GlobalData::GlobalData()
m_enableDynamicLOD = TRUE;
m_enableStaticLOD = TRUE;
m_rightMouseAlwaysScrolls = FALSE;
m_jpegQuality = 80;
m_useWaterPlane = FALSE;
m_useCloudPlane = FALSE;
m_downwindAngle = ( -0.785f );//Northeast!
Expand Down Expand Up @@ -1189,6 +1190,7 @@ void GlobalData::parseGameDataDefinition( INI* ini )
TheWritableGlobalData->m_useAlternateMouse = optionPref.getAlternateMouseModeEnabled();
TheWritableGlobalData->m_clientRetaliationModeEnabled = optionPref.getRetaliationModeEnabled();
TheWritableGlobalData->m_doubleClickAttackMove = optionPref.getDoubleClickAttackMoveEnabled();
TheWritableGlobalData->m_jpegQuality = optionPref.getJPEGQuality();
TheWritableGlobalData->m_keyboardScrollFactor = optionPref.getScrollFactor();
TheWritableGlobalData->m_drawScrollAnchor = optionPref.getDrawScrollAnchor();
TheWritableGlobalData->m_moveScrollAnchor = optionPref.getMoveScrollAnchor();
Expand Down
1 change: 1 addition & 0 deletions Generals/Code/GameEngine/Source/Common/MessageStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ const char *GameMessage::getCommandTypeAsString(GameMessage::Type t)
CASE_LABEL(MSG_META_BEGIN_PREFER_SELECTION)
CASE_LABEL(MSG_META_END_PREFER_SELECTION)
CASE_LABEL(MSG_META_TAKE_SCREENSHOT)
CASE_LABEL(MSG_META_TAKE_SCREENSHOT_PNG)
CASE_LABEL(MSG_META_ALL_CHEER)
CASE_LABEL(MSG_META_TOGGLE_ATTACKMOVE)
CASE_LABEL(MSG_META_BEGIN_CAMERA_ROTATE_LEFT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3418,7 +3418,15 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage
case GameMessage::MSG_META_TAKE_SCREENSHOT:
{
if (TheDisplay)
TheDisplay->takeScreenShot();
TheDisplay->takeScreenShot(SCREENSHOT_JPEG);
disp = DESTROY_MESSAGE;
break;
}

case GameMessage::MSG_META_TAKE_SCREENSHOT_PNG:
{
if (TheDisplay)
TheDisplay->takeScreenShot(SCREENSHOT_PNG);
disp = DESTROY_MESSAGE;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ static const LookupListRec GameMessageMetaTypeNames[] =
{ "END_PREFER_SELECTION", GameMessage::MSG_META_END_PREFER_SELECTION },

{ "TAKE_SCREENSHOT", GameMessage::MSG_META_TAKE_SCREENSHOT },
{ "TAKE_SCREENSHOT_PNG", GameMessage::MSG_META_TAKE_SCREENSHOT_PNG },
{ "ALL_CHEER", GameMessage::MSG_META_ALL_CHEER },

{ "BEGIN_CAMERA_ROTATE_LEFT", GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_LEFT },
Expand Down Expand Up @@ -813,6 +814,26 @@ MetaMapRec *MetaMap::getMetaMapRec(GameMessage::Type t)
map->m_usableIn = COMMANDUSABLE_GAME;
}
}
{
MetaMapRec *map = TheMetaMap->getMetaMapRec(GameMessage::MSG_META_TAKE_SCREENSHOT);
if (map->m_key == MK_NONE)
{
map->m_key = MK_F12;
map->m_transition = DOWN;
map->m_modState = NONE;
map->m_usableIn = COMMANDUSABLE_EVERYWHERE;
}
}
{
MetaMapRec *map = TheMetaMap->getMetaMapRec(GameMessage::MSG_META_TAKE_SCREENSHOT_PNG);
if (map->m_key == MK_NONE)
{
map->m_key = MK_F12;
map->m_transition = DOWN;
map->m_modState = CTRL;
map->m_usableIn = COMMANDUSABLE_EVERYWHERE;
}
}

#if defined(RTS_DEBUG)
{
Expand Down
2 changes: 2 additions & 0 deletions Generals/Code/GameEngineDevice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ set(GAMEENGINEDEVICE_SRC
Source/W3DDevice/GameClient/W3DDebugDisplay.cpp
Source/W3DDevice/GameClient/W3DDebugIcons.cpp
Source/W3DDevice/GameClient/W3DDisplay.cpp
Source/W3DDevice/GameClient/W3DScreenshot.cpp
Source/W3DDevice/GameClient/W3DDisplayString.cpp
Source/W3DDevice/GameClient/W3DDisplayStringManager.cpp
Source/W3DDevice/GameClient/W3DDynamicLight.cpp
Expand Down Expand Up @@ -200,6 +201,7 @@ target_link_libraries(g_gameenginedevice PRIVATE
corei_gameenginedevice_private
gi_always
gi_main
stb
)

target_link_libraries(g_gameenginedevice PUBLIC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class W3DDisplay : public Display

virtual VideoBuffer* createVideoBuffer() ; ///< Create a video buffer that can be used for this display

virtual void takeScreenShot(); //save screenshot to file
virtual void takeScreenShot(ScreenshotFormat format); //save screenshot in specified format
virtual void toggleMovieCapture(); //enable AVI or frame capture mode.

virtual void toggleLetterBox(); ///<enabled letter-boxed display
Expand Down
Loading
Loading