Skip to content

Commit e2a07c4

Browse files
committed
Move W3DScreenshot implementation to game-specific directories
1 parent 5d269f7 commit e2a07c4

File tree

5 files changed

+157
-1
lines changed

5 files changed

+157
-1
lines changed

Core/GameEngineDevice/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ set(GAMEENGINEDEVICE_SRC
174174
# Source/W3DDevice/GameClient/W3DTerrainVisual.cpp
175175
# Source/W3DDevice/GameClient/W3DTreeBuffer.cpp
176176
Source/W3DDevice/GameClient/W3DVideoBuffer.cpp
177-
Source/W3DDevice/GameClient/W3DScreenshot.cpp
178177
# Source/W3DDevice/GameClient/W3DView.cpp
179178
# Source/W3DDevice/GameClient/W3dWaypointBuffer.cpp
180179
# Source/W3DDevice/GameClient/W3DWebBrowser.cpp

Generals/Code/GameEngineDevice/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ set(GAMEENGINEDEVICE_SRC
140140
Source/W3DDevice/GameClient/W3DDebugDisplay.cpp
141141
Source/W3DDevice/GameClient/W3DDebugIcons.cpp
142142
Source/W3DDevice/GameClient/W3DDisplay.cpp
143+
Source/W3DDevice/GameClient/W3DScreenshot.cpp
143144
Source/W3DDevice/GameClient/W3DDisplayString.cpp
144145
Source/W3DDevice/GameClient/W3DDisplayStringManager.cpp
145146
Source/W3DDevice/GameClient/W3DDynamicLight.cpp

GeneralsMD/Code/GameEngineDevice/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ set(GAMEENGINEDEVICE_SRC
151151
Source/W3DDevice/GameClient/W3DDebugDisplay.cpp
152152
Source/W3DDevice/GameClient/W3DDebugIcons.cpp
153153
Source/W3DDevice/GameClient/W3DDisplay.cpp
154+
Source/W3DDevice/GameClient/W3DScreenshot.cpp
154155
Source/W3DDevice/GameClient/W3DDisplayString.cpp
155156
Source/W3DDevice/GameClient/W3DDisplayStringManager.cpp
156157
Source/W3DDevice/GameClient/W3DDynamicLight.cpp
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 Electronic Arts Inc.
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include <stdlib.h>
20+
#include <windows.h>
21+
#include <io.h>
22+
23+
#define STB_IMAGE_WRITE_IMPLEMENTATION
24+
#include <stb_image_write.h>
25+
26+
#include "W3DDevice/GameClient/W3DScreenshot.h"
27+
#include "Common/GlobalData.h"
28+
#include "GameClient/InGameUI.h"
29+
#include "GameClient/GameText.h"
30+
#include "WW3D2/dx8wrapper.h"
31+
#include "WW3D2/surface.h"
32+
33+
struct ScreenshotThreadData
34+
{
35+
unsigned char* imageData;
36+
unsigned int width;
37+
unsigned int height;
38+
char pathname[1024];
39+
char leafname[256];
40+
int quality;
41+
ScreenshotFormat format;
42+
};
43+
44+
static DWORD WINAPI screenshotThreadFunc(LPVOID param)
45+
{
46+
ScreenshotThreadData* data = (ScreenshotThreadData*)param;
47+
48+
int result = 0;
49+
if (data->format == SCREENSHOT_JPEG)
50+
{
51+
result = stbi_write_jpg(data->pathname, data->width, data->height, 3, data->imageData, data->quality);
52+
}
53+
else if (data->format == SCREENSHOT_PNG)
54+
{
55+
result = stbi_write_png(data->pathname, data->width, data->height, 3, data->imageData, data->width * 3);
56+
}
57+
58+
if (!result) {
59+
OutputDebugStringA("Failed to write screenshot\n");
60+
}
61+
62+
delete [] data->imageData;
63+
delete data;
64+
65+
return 0;
66+
}
67+
68+
void W3D_TakeCompressedScreenshot(ScreenshotFormat format, int quality = 0)
69+
{
70+
char leafname[256];
71+
char pathname[1024];
72+
static int jpegFrameNumber = 1;
73+
static int pngFrameNumber = 1;
74+
75+
int* frameNumber = (format == SCREENSHOT_JPEG) ? &jpegFrameNumber : &pngFrameNumber;
76+
const char* extension = (format == SCREENSHOT_JPEG) ? "jpg" : "png";
77+
78+
Bool done = false;
79+
while (!done) {
80+
sprintf(leafname, "sshot%.3d.%s", (*frameNumber)++, extension);
81+
strcpy(pathname, TheGlobalData->getPath_UserData().str());
82+
strlcat(pathname, leafname, ARRAY_SIZE(pathname));
83+
if (_access(pathname, 0) == -1)
84+
done = true;
85+
}
86+
87+
SurfaceClass* surface = DX8Wrapper::_Get_DX8_Back_Buffer();
88+
SurfaceClass::SurfaceDescription surfaceDesc;
89+
surface->Get_Description(surfaceDesc);
90+
91+
SurfaceClass* surfaceCopy = NEW_REF(SurfaceClass, (DX8Wrapper::_Create_DX8_Surface(surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format)));
92+
DX8Wrapper::_Copy_DX8_Rects(surface->Peek_D3D_Surface(), NULL, 0, surfaceCopy->Peek_D3D_Surface(), NULL);
93+
94+
surface->Release_Ref();
95+
surface = NULL;
96+
97+
struct Rect
98+
{
99+
int Pitch;
100+
void* pBits;
101+
} lrect;
102+
103+
lrect.pBits = surfaceCopy->Lock(&lrect.Pitch);
104+
if (lrect.pBits == NULL)
105+
{
106+
surfaceCopy->Release_Ref();
107+
return;
108+
}
109+
110+
unsigned int x, y, index, index2;
111+
unsigned int width = surfaceDesc.Width;
112+
unsigned int height = surfaceDesc.Height;
113+
114+
unsigned char* image = new unsigned char[3 * width * height];
115+
116+
for (y = 0; y < height; y++)
117+
{
118+
for (x = 0; x < width; x++)
119+
{
120+
index = 3 * (x + y * width);
121+
index2 = y * lrect.Pitch + 4 * x;
122+
123+
image[index] = *((unsigned char*)lrect.pBits + index2 + 2);
124+
image[index + 1] = *((unsigned char*)lrect.pBits + index2 + 1);
125+
image[index + 2] = *((unsigned char*)lrect.pBits + index2 + 0);
126+
}
127+
}
128+
129+
surfaceCopy->Unlock();
130+
surfaceCopy->Release_Ref();
131+
surfaceCopy = NULL;
132+
133+
if (quality <= 0 && format == SCREENSHOT_JPEG)
134+
quality = TheGlobalData->m_jpegQuality;
135+
136+
ScreenshotThreadData* threadData = new ScreenshotThreadData();
137+
threadData->imageData = image;
138+
threadData->width = width;
139+
threadData->height = height;
140+
threadData->quality = quality;
141+
threadData->format = format;
142+
strcpy(threadData->pathname, pathname);
143+
strcpy(threadData->leafname, leafname);
144+
145+
DWORD threadId;
146+
HANDLE hThread = CreateThread(NULL, 0, screenshotThreadFunc, threadData, 0, &threadId);
147+
if (hThread) {
148+
CloseHandle(hThread);
149+
}
150+
151+
UnicodeString ufileName;
152+
ufileName.translate(leafname);
153+
TheInGameUI->message(TheGameText->fetch("GUI:ScreenCapture"), ufileName.str());
154+
}
155+

0 commit comments

Comments
 (0)