Skip to content

Commit 575e090

Browse files
committed
Implement threaded JPEG screenshot for Generals
1 parent a51e614 commit 575e090

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class W3DDisplay : public Display
121121
virtual VideoBuffer* createVideoBuffer( void ) ; ///< Create a video buffer that can be used for this display
122122

123123
virtual void takeScreenShot(void); //save screenshot to file
124+
virtual void takeScreenShotCompressed(void); //save compressed screenshot to file (JPG/PNG) without stalling
124125
virtual void toggleMovieCapture(void); //enable AVI or frame capture mode.
125126

126127
virtual void toggleLetterBox(void); ///<enabled letter-boxed display

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ static void drawFramerateBar(void);
3939
#include <windows.h>
4040
#include <io.h>
4141
#include <time.h>
42+
#include <thread>
43+
#include <memory>
44+
45+
#define STB_IMAGE_WRITE_IMPLEMENTATION
46+
#include <stb_image_write.h>
4247

4348
// USER INCLUDES //////////////////////////////////////////////////////////////
4449
#include "Common/FramePacer.h"
@@ -3022,6 +3027,85 @@ void W3DDisplay::takeScreenShot(void)
30223027
TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str());
30233028
}
30243029

3030+
void W3DDisplay::takeScreenShotCompressed(void)
3031+
{
3032+
char leafname[256];
3033+
char pathname[1024];
3034+
static int frame_number = 1;
3035+
3036+
Bool done = false;
3037+
while (!done) {
3038+
sprintf(leafname, "sshot%.3d.jpg", frame_number++);
3039+
strcpy(pathname, TheGlobalData->getPath_UserData().str());
3040+
strlcat(pathname, leafname, ARRAY_SIZE(pathname));
3041+
if (_access(pathname, 0) == -1)
3042+
done = true;
3043+
}
3044+
3045+
SurfaceClass* surface = DX8Wrapper::_Get_DX8_Back_Buffer();
3046+
SurfaceClass::SurfaceDescription surfaceDesc;
3047+
surface->Get_Description(surfaceDesc);
3048+
3049+
SurfaceClass* surfaceCopy = NEW_REF(SurfaceClass, (DX8Wrapper::_Create_DX8_Surface(surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format)));
3050+
DX8Wrapper::_Copy_DX8_Rects(surface->Peek_D3D_Surface(), NULL, 0, surfaceCopy->Peek_D3D_Surface(), NULL);
3051+
3052+
surface->Release_Ref();
3053+
surface = NULL;
3054+
3055+
struct Rect
3056+
{
3057+
int Pitch;
3058+
void* pBits;
3059+
} lrect;
3060+
3061+
lrect.pBits = surfaceCopy->Lock(&lrect.Pitch);
3062+
if (lrect.pBits == NULL)
3063+
{
3064+
surfaceCopy->Release_Ref();
3065+
return;
3066+
}
3067+
3068+
unsigned int x, y, index, index2;
3069+
unsigned int width = surfaceDesc.Width;
3070+
unsigned int height = surfaceDesc.Height;
3071+
3072+
std::shared_ptr<unsigned char> imageData(new unsigned char[3 * width * height],
3073+
std::default_delete<unsigned char[]>());
3074+
unsigned char* image = imageData.get();
3075+
3076+
for (y = 0; y < height; y++)
3077+
{
3078+
for (x = 0; x < width; x++)
3079+
{
3080+
index = 3 * (x + y * width);
3081+
index2 = y * lrect.Pitch + 4 * x;
3082+
3083+
image[index] = *((unsigned char*)lrect.pBits + index2 + 2);
3084+
image[index + 1] = *((unsigned char*)lrect.pBits + index2 + 1);
3085+
image[index + 2] = *((unsigned char*)lrect.pBits + index2 + 0);
3086+
}
3087+
}
3088+
3089+
surfaceCopy->Unlock();
3090+
surfaceCopy->Release_Ref();
3091+
surfaceCopy = NULL;
3092+
3093+
std::string pathnameCopy(pathname);
3094+
std::string leafnameCopy(leafname);
3095+
3096+
std::thread([imageData, width, height, pathnameCopy, leafnameCopy]() {
3097+
int result = stbi_write_jpg(pathnameCopy.c_str(), width, height, 3, imageData.get(), 90);
3098+
3099+
if (!result) {
3100+
OutputDebugStringA("Failed to write screenshot JPEG\n");
3101+
}
3102+
}).detach();
3103+
3104+
UnicodeString ufileName;
3105+
ufileName.translate(leafnameCopy.c_str());
3106+
TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str());
3107+
}
3108+
30253109
/** Start/Stop capturing an AVI movie*/
30263110
void W3DDisplay::toggleMovieCapture(void)
30273111
{

0 commit comments

Comments
 (0)