@@ -81,36 +81,40 @@ void NGMP_OnlineServicesManager::GetAndParseServiceConfig(std::function<void(voi
8181
8282void NGMP_OnlineServicesManager::CaptureScreenshotToDisk ()
8383{
84- std::vector<unsigned char > vecBuffer = NGMP_OnlineServicesManager::CaptureScreenshot (false );
84+ // create dirs
85+ std::string strScreenshotsDir = std::format (" {}/GeneralsOnlineScreenshots/" , TheGlobalData->getPath_UserData ().str ());
8586
86- if (!vecBuffer. empty ( ))
87+ if (!std::filesystem::exists (strScreenshotsDir ))
8788 {
88- char GameDir[MAX_PATH + 1 ] = {};
89- ::GetCurrentDirectoryA (MAX_PATH + 1u , GameDir);
90- std::string strScreenshotsDir = std::format (" {}/GeneralsOnlineScreenshots/" , TheGlobalData->getPath_UserData ().str ());
91-
92- if (!std::filesystem::exists (strScreenshotsDir))
93- {
94- std::filesystem::create_directory (strScreenshotsDir);
95- }
96-
97- // write to disk
98- auto now = std::chrono::system_clock::now ();
99- auto in_time_t = std::chrono::system_clock::to_time_t (now);
100- std::stringstream ss;
101- ss << std::put_time (std::localtime (&in_time_t ), " GeneralsOnline_Screenshot_%Y-%m-%d-%H-%M-%S.jpg" );
89+ std::filesystem::create_directory (strScreenshotsDir);
90+ }
10291
103- std::string strFilePath = std::format (" {}/{}" , strScreenshotsDir.c_str (), ss.str ().c_str ());
92+ // calculate path
93+ auto now = std::chrono::system_clock::now ();
94+ auto in_time_t = std::chrono::system_clock::to_time_t (now);
95+ std::stringstream ss;
96+ ss << std::put_time (std::localtime (&in_time_t ), " GeneralsOnline_Screenshot_%Y-%m-%d-%H-%M-%S.jpg" );
10497
105- FILE * pFile = fopen (strFilePath.c_str (), " wb" );
106- fwrite (vecBuffer.data (), sizeof (uint8_t ), vecBuffer.size (), pFile);
107- fclose (pFile);
98+ std::string strFilePath = std::format (" {}/{}" , strScreenshotsDir.c_str (), ss.str ().c_str ());
10899
109- // UI output (if ingame)
100+ // do UI output immediately on mainthread (if ingame)
101+ if (TheInGameUI != nullptr )
102+ {
110103 UnicodeString ufileName;
111104 ufileName.translate (AsciiString (strFilePath.c_str ()));
112105 TheInGameUI->message (TheGameText->fetch (" GUI:ScreenCapture" ), ufileName.str ());
113106 }
107+
108+ NGMP_OnlineServicesManager::CaptureScreenshot (false , [strFilePath](std::vector<unsigned char > vecBuffer)
109+ {
110+ if (!vecBuffer.empty ())
111+ {
112+ // write to disk
113+ FILE * pFile = fopen (strFilePath.c_str (), " wb" );
114+ fwrite (vecBuffer.data (), sizeof (uint8_t ), vecBuffer.size (), pFile);
115+ fclose (pFile);
116+ }
117+ });
114118}
115119
116120NGMP_OnlineServicesManager* NGMP_OnlineServicesManager::m_pOnlineServicesManager = nullptr ;
@@ -341,9 +345,13 @@ void NGMP_OnlineServicesManager::ContinueUpdate()
341345}
342346
343347
344- std::vector<unsigned char > NGMP_OnlineServicesManager::CaptureScreenshot ( bool bResizeForTransmit )
348+ void NGMP_OnlineServicesManager::CaptureScreenshot ( bool bResizeForTransmit, std::function< void (std:: vector<unsigned char >)> cbOnDataAvailable )
345349{
346- std::vector<unsigned char > vecData;
350+ // no callback, nothing to do
351+ if (cbOnDataAvailable == nullptr )
352+ {
353+ return ;
354+ }
347355
348356 SurfaceClass* surface = DX8Wrapper::_Get_DX8_Back_Buffer ();
349357
@@ -357,68 +365,89 @@ std::vector<unsigned char> NGMP_OnlineServicesManager::CaptureScreenshot(bool bR
357365
358366 D3DDISPLAYMODE mode;
359367 if (FAILED (hr = DX8Wrapper::_Get_D3D_Device8 ()->GetDisplayMode (&mode)))
360- return vecData;
368+ {
369+ cbOnDataAvailable (std::vector<unsigned char >());
370+ return ;
371+ }
361372
362373 LPDIRECT3DSURFACE8 surf;
363374 if (FAILED (hr = DX8Wrapper::_Get_D3D_Device8 ()->CreateImageSurface (mode.Width , mode.Height ,
364375 D3DFMT_A8R8G8B8 , &surf)))
365- return vecData;
376+ {
377+ cbOnDataAvailable (std::vector<unsigned char >());
378+ return ;
379+ }
366380
367381 if (FAILED (hr = DX8Wrapper::_Get_D3D_Device8 ()->GetFrontBuffer (surf))) {
368382 surf->Release ();
369- return vecData;
383+ {
384+ cbOnDataAvailable (std::vector<unsigned char >());
385+ return ;
386+ }
370387 }
371388
389+ // gather all our data
372390 int pitch = 0 ;
373391 void * pBits = surfaceCopy->Lock (&pitch);
374392
375393 unsigned char * rgbData = new unsigned char [surfaceDesc.Width * surfaceDesc.Height * 3 ];
376394
377395 int width = surfaceDesc.Width ;
378396 int height = surfaceDesc.Height ;
379- for (int y = 0 ; y < height; ++y) {
380- uint8_t * row = (uint8_t *)pBits + y * pitch;
381- for (int x = 0 ; x < width; ++x) {
382- int srcIndex = x * 4 ;
383- int dstIndex = (y * width + x) * 3 ;
384-
385- rgbData[dstIndex + 0 ] = row[srcIndex + 2 ]; // R
386- rgbData[dstIndex + 1 ] = row[srcIndex + 1 ]; // G
387- rgbData[dstIndex + 2 ] = row[srcIndex + 0 ]; // B
388- }
389- }
390397
391- // resize
392- unsigned char * pBufferToWrite = rgbData;
393- if (bResizeForTransmit)
394- {
395- int new_width = 844 ;
396- int new_height = 506 ;
397- int channels = 3 ;
398- unsigned char * resized = new unsigned char [new_width * new_height * channels];
398+ // release the image surface
399+ surf->Release ();
399400
400- stbir_resize_uint8 (rgbData, surfaceDesc. Width , surfaceDesc. Height , 0 ,
401- resized, new_width, new_height, 0 ,
402- channels
403- ) ;
401+ // process on thread
402+ std::thread* pNewThread = new std::thread ([cbOnDataAvailable, width, height, pBits, pitch, rgbData, bResizeForTransmit]()
403+ {
404+ std::vector< unsigned char > vecData ;
404405
405- // update data
406- width = new_width;
407- height = new_height;
408- pBufferToWrite = resized;
409- }
410- // end resize
406+ int finalWidth = width;
407+ int finalHeight = height;
411408
412- stbi_write_jpg_to_func ([](void * context, void * data, int size)
413- {
414- std::vector<unsigned char >* buffer = static_cast <std::vector<unsigned char >*>(context);
415- buffer->insert (buffer->end (), (unsigned char *)data, (unsigned char *)data + size);
416- }, &vecData, width, height, 3 , pBufferToWrite, bResizeForTransmit ? 0 : 50 );
417-
418- // release the image surface
419- surf->Release ();
409+ for (int y = 0 ; y < height; ++y) {
410+ uint8_t * row = (uint8_t *)pBits + y * pitch;
411+ for (int x = 0 ; x < width; ++x) {
412+ int srcIndex = x * 4 ;
413+ int dstIndex = (y * width + x) * 3 ;
414+
415+ rgbData[dstIndex + 0 ] = row[srcIndex + 2 ]; // R
416+ rgbData[dstIndex + 1 ] = row[srcIndex + 1 ]; // G
417+ rgbData[dstIndex + 2 ] = row[srcIndex + 0 ]; // B
418+ }
419+ }
420+
421+ // resize
422+ unsigned char * pBufferToWrite = rgbData;
423+ if (bResizeForTransmit)
424+ {
425+ int new_width = 844 ;
426+ int new_height = 506 ;
427+ int channels = 3 ;
428+ unsigned char * resized = new unsigned char [new_width * new_height * channels];
429+
430+ stbir_resize_uint8 (rgbData, width, height, 0 ,
431+ resized, new_width, new_height, 0 ,
432+ channels
433+ );
434+
435+ // update data
436+ finalWidth = new_width;
437+ finalHeight = new_height;
438+ pBufferToWrite = resized;
439+ }
440+ // end resize
420441
421- return vecData;
442+ stbi_write_jpg_to_func ([](void * context, void * data, int size)
443+ {
444+ std::vector<unsigned char >* buffer = static_cast <std::vector<unsigned char >*>(context);
445+ buffer->insert (buffer->end (), (unsigned char *)data, (unsigned char *)data + size);
446+ }, &vecData, finalWidth, finalHeight, 3 , pBufferToWrite, bResizeForTransmit ? 0 : 90 );
447+
448+ cbOnDataAvailable (vecData);
449+ });
450+ SetThreadDescription (static_cast <HANDLE >(pNewThread->native_handle ()), L" SCREENSHOT THREAD" );
422451}
423452
424453void NGMP_OnlineServicesManager::CancelUpdate ()
0 commit comments