Skip to content

Commit a51e614

Browse files
committed
Implement threaded JPEG screenshot for GeneralsMD
1 parent ed481d4 commit a51e614

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

GeneralsMD/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

GeneralsMD/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"
@@ -3141,6 +3146,85 @@ void W3DDisplay::takeScreenShot(void)
31413146
TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str());
31423147
}
31433148

3149+
void W3DDisplay::takeScreenShotCompressed(void)
3150+
{
3151+
char leafname[256];
3152+
char pathname[1024];
3153+
static int frame_number = 1;
3154+
3155+
Bool done = false;
3156+
while (!done) {
3157+
sprintf(leafname, "sshot%.3d.jpg", frame_number++);
3158+
strcpy(pathname, TheGlobalData->getPath_UserData().str());
3159+
strlcat(pathname, leafname, ARRAY_SIZE(pathname));
3160+
if (_access(pathname, 0) == -1)
3161+
done = true;
3162+
}
3163+
3164+
SurfaceClass* surface = DX8Wrapper::_Get_DX8_Back_Buffer();
3165+
SurfaceClass::SurfaceDescription surfaceDesc;
3166+
surface->Get_Description(surfaceDesc);
3167+
3168+
SurfaceClass* surfaceCopy = NEW_REF(SurfaceClass, (DX8Wrapper::_Create_DX8_Surface(surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format)));
3169+
DX8Wrapper::_Copy_DX8_Rects(surface->Peek_D3D_Surface(), NULL, 0, surfaceCopy->Peek_D3D_Surface(), NULL);
3170+
3171+
surface->Release_Ref();
3172+
surface = NULL;
3173+
3174+
struct Rect
3175+
{
3176+
int Pitch;
3177+
void* pBits;
3178+
} lrect;
3179+
3180+
lrect.pBits = surfaceCopy->Lock(&lrect.Pitch);
3181+
if (lrect.pBits == NULL)
3182+
{
3183+
surfaceCopy->Release_Ref();
3184+
return;
3185+
}
3186+
3187+
unsigned int x, y, index, index2;
3188+
unsigned int width = surfaceDesc.Width;
3189+
unsigned int height = surfaceDesc.Height;
3190+
3191+
std::shared_ptr<unsigned char> imageData(new unsigned char[3 * width * height],
3192+
std::default_delete<unsigned char[]>());
3193+
unsigned char* image = imageData.get();
3194+
3195+
for (y = 0; y < height; y++)
3196+
{
3197+
for (x = 0; x < width; x++)
3198+
{
3199+
index = 3 * (x + y * width);
3200+
index2 = y * lrect.Pitch + 4 * x;
3201+
3202+
image[index] = *((unsigned char*)lrect.pBits + index2 + 2);
3203+
image[index + 1] = *((unsigned char*)lrect.pBits + index2 + 1);
3204+
image[index + 2] = *((unsigned char*)lrect.pBits + index2 + 0);
3205+
}
3206+
}
3207+
3208+
surfaceCopy->Unlock();
3209+
surfaceCopy->Release_Ref();
3210+
surfaceCopy = NULL;
3211+
3212+
std::string pathnameCopy(pathname);
3213+
std::string leafnameCopy(leafname);
3214+
3215+
std::thread([imageData, width, height, pathnameCopy, leafnameCopy]() {
3216+
int result = stbi_write_jpg(pathnameCopy.c_str(), width, height, 3, imageData.get(), 90);
3217+
3218+
if (!result) {
3219+
OutputDebugStringA("Failed to write screenshot JPEG\n");
3220+
}
3221+
}).detach();
3222+
3223+
UnicodeString ufileName;
3224+
ufileName.translate(leafnameCopy.c_str());
3225+
TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str());
3226+
}
3227+
31443228
/** Start/Stop capturing an AVI movie*/
31453229
void W3DDisplay::toggleMovieCapture(void)
31463230
{

0 commit comments

Comments
 (0)