feat(screenshot): Add threaded JPEG/PNG screenshots without game stalls#1785
feat(screenshot): Add threaded JPEG/PNG screenshots without game stalls#1785bobtista wants to merge 24 commits intoTheSuperHackers:mainfrom
Conversation
20a3df1 to
37bd840
Compare
|
Some initial thoughts:
|
|
Agree with Stubbjax. JPG 90 is big file. Better make it default 80. Replace BMP screenshot with PNG screenshot. PNG is lossless compressed and always better than BMP. Make F12 take JPG 80 screenshot. Make CTRL+F12 take PNG screenshot. Make JPG Quality adjustable. Remove the old BMP code(s) and only use the new code for screenshot. |
|
Regarding Github formatting: When you write
Then it will not close this report when this is merged. Please read up on it here: |
RE moving logic to core, I moved what I could to core - but there are a lot more files that need to be moved to core before this can be moved there eg WWVegas/WW3D2/* |
3535e1e to
efc773f
Compare
Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScreenshot.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScreenshot.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScreenshot.cpp
Outdated
Show resolved
Hide resolved
977a6dc to
f8162f3
Compare
d7e8a8d to
d197bdd
Compare
d197bdd to
9669966
Compare
|
Needs rebase. |
9669966 to
4897b0b
Compare
Done |
Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DScreenshot.h
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/stb_image_write_impl.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScreenshot.cpp
Show resolved
Hide resolved
Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp
Outdated
Show resolved
Hide resolved
Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp
Outdated
Show resolved
Hide resolved
9c99306 to
de35e57
Compare
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp
Show resolved
Hide resolved
| Bool m_clientRetaliationModeEnabled; | ||
| Bool m_doubleClickAttackMove; | ||
| Bool m_rightMouseAlwaysScrolls; | ||
| Int m_jpegQuality; |
There was a problem hiding this comment.
m_jpegQuality is never initialized in the constructor
Every neighboring member in this struct (m_rightMouseAlwaysScrolls at GlobalData.cpp:647, m_useWaterPlane at GlobalData.cpp:648, etc.) is explicitly initialized in the GlobalData::GlobalData() constructor, but m_jpegQuality is not. It only gets set later in parseGameDataDefinition via optionPref.getJPEGQuality().
This means m_jpegQuality holds an indeterminate value between construction and the parseGameDataDefinition call. While screenshots are unlikely to be taken in that window during normal gameplay, this is still a correctness defect that should be fixed for consistency and safety. The same issue exists in the GeneralsMD mirror file.
Add initialization in both GlobalData::GlobalData() constructors, for example after m_rightMouseAlwaysScrolls = FALSE;:
m_jpegQuality = 80;Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngine/Include/Common/GlobalData.h
Line: 145:145
Comment:
**`m_jpegQuality` is never initialized in the constructor**
Every neighboring member in this struct (`m_rightMouseAlwaysScrolls` at `GlobalData.cpp:647`, `m_useWaterPlane` at `GlobalData.cpp:648`, etc.) is explicitly initialized in the `GlobalData::GlobalData()` constructor, but `m_jpegQuality` is not. It only gets set later in `parseGameDataDefinition` via `optionPref.getJPEGQuality()`.
This means `m_jpegQuality` holds an indeterminate value between construction and the `parseGameDataDefinition` call. While screenshots are unlikely to be taken in that window during normal gameplay, this is still a correctness defect that should be fixed for consistency and safety. The same issue exists in the GeneralsMD mirror file.
Add initialization in both `GlobalData::GlobalData()` constructors, for example after `m_rightMouseAlwaysScrolls = FALSE;`:
```cpp
m_jpegQuality = 80;
```
How can I resolve this? If you propose a fix, please make it concise.| target_sources(g_gameenginedevice PRIVATE | ||
| # Source/W3DDevice/GameClient/stb_image_write_impl.cpp | ||
| ) | ||
|
|
||
| set_source_files_properties( | ||
| # Source/W3DDevice/GameClient/stb_image_write_impl.cpp | ||
| PROPERTIES | ||
| SKIP_PRECOMPILE_HEADERS ON | ||
| ) |
There was a problem hiding this comment.
Empty CMake commands left behind after commenting out source
These target_sources and set_source_files_properties blocks are entirely commented out inside, resulting in empty CMake commands. Since stb_image_write_impl.cpp is compiled in the Core CMakeLists now, consider removing these empty shells entirely rather than leaving commented-out scaffolding. The same applies to the GeneralsMD mirror CMakeLists.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngineDevice/CMakeLists.txt
Line: 207:215
Comment:
**Empty CMake commands left behind after commenting out source**
These `target_sources` and `set_source_files_properties` blocks are entirely commented out inside, resulting in empty CMake commands. Since `stb_image_write_impl.cpp` is compiled in the Core CMakeLists now, consider removing these empty shells entirely rather than leaving commented-out scaffolding. The same applies to the GeneralsMD mirror CMakeLists.
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.Add takeScreenShotCompressed() to Display interface
Implement threaded JPEG screenshot for Generals Link stb library to GameEngineDevice targets Remove excessive comments from screenshot implementation
Add shared screenshot implementation in Core
Move W3DScreenshot implementation to game-specific directories Fix include order for VC6 precompiled headers Remove default parameter from function definition Move STB implementation to separate file to avoid PCH issues Include screenshot implementation directly in W3DDisplay.cpp to avoid PCH issues Use Windows constants and switch statement in screenshot code Use vcpkg for stb dependency with FetchContent fallback
…ince it's included in W3DDisplay.cpp
Move stb_image_write_impl.cpp from game-specific directories to Core since it's identical between Generals and GeneralsMD and contains only STB library implementation code with no game-specific logic.
…o nullptr, strcpy to strlcpy, fix thread leak
…on unit instead of #including it
c4673ea to
45c0339
Compare
| UnicodeString ufileName; | ||
| ufileName.translate(leafname); | ||
| TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str()); |
There was a problem hiding this comment.
Success message shown even when screenshot fails
If CreateThread fails (line 144), the image data and thread data are cleaned up but the function continues to display the "screen captured" message to the user at line 154. Consider moving the TheInGameUI->message(...) call into the if (hThread) block so it only displays on success, or at least log the failure more visibly. The same applies to the GeneralsMD mirror file.
Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScreenshot.cpp
Line: 152:154
Comment:
**Success message shown even when screenshot fails**
If `CreateThread` fails (line 144), the image data and thread data are cleaned up but the function continues to display the "screen captured" message to the user at line 154. Consider moving the `TheInGameUI->message(...)` call into the `if (hThread)` block so it only displays on success, or at least log the failure more visibly. The same applies to the GeneralsMD mirror file.
How can I resolve this? If you propose a fix, please make it concise.
Additional Comments (1)
The old Prompt To Fix With AIThis is a comment left during a code review.
Path: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
Line: 2807:2880
Comment:
**Dead `CreateBMPFile` function left behind**
The old `takeScreenShot` method (which was the only caller of `CreateBMPFile`) has been removed, leaving this ~75-line static function as dead code. It will produce a compiler warning for unused static function. Consider removing it since BMP screenshot functionality is fully replaced by the new JPEG/PNG implementation. The same applies to the GeneralsMD mirror file.
How can I resolve this? If you propose a fix, please make it concise. |
Summary
Replaces the old BMP screenshot with compressed JPEG screenshots that don't stall the game, and adds PNG support.
Closes #1555
Closes #106 ... sort of
Adds a new screenshot function using the stb_image_write library with background threading:
Notes
Testing