port: grp.SaveScreenShot via next-frame swapchain readback + JPEG
CPythonGraphic::SaveScreenShot queues a readback of the next presented frame (ScreenShotHost -> VulkanWindow::request_frame); WriteScreenShot runs the rest of 40250's function verbatim (X8R8G8B8 rows, SaveJPEG, EXIF tag). jpeg_save is encoded with stb_image_write. SHGetSpecialFolderPath returns $HOME/Documents (else cwd); CreateDirectory/_access/jpeg_save accept '\\'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c21e012965
commit
bda85eea50
@@ -209,6 +209,11 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
|
||||
target_link_libraries(port_spherelib_test PRIVATE port_platform)
|
||||
add_test(NAME port.spherelib COMMAND $<TARGET_FILE:port_spherelib_test>)
|
||||
|
||||
# grp.SaveScreenShot: the host frame request and the 40250 JPEG write behind it.
|
||||
add_executable(port_screenshot_test ${PROJECT_SOURCE_DIR}/tests/port/port_screenshot_test.cpp)
|
||||
target_link_libraries(port_screenshot_test PRIVATE port_platform)
|
||||
add_test(NAME port.screenshot COMMAND $<TARGET_FILE:port_screenshot_test>)
|
||||
|
||||
# 批次 2V1: Packet.h struct sizes against the classic wire layouts.
|
||||
add_executable(port_packet_test ${PROJECT_SOURCE_DIR}/tests/port/port_packet_test.cpp
|
||||
${PROJECT_SOURCE_DIR}/tests/port/port_packet_test_wire.cpp)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int jpeg_save(unsigned char*data_d, int width, int height, int quality, const char*filename);
|
||||
int jpeg_save_to_file(unsigned char*data_d, int width, int height, int quality, FILE*fi);
|
||||
int jpeg_save_to_mem(unsigned char*data_d, int width, int height, int quality, unsigned char*dest, int destsize);
|
||||
int jpeg_load(const char*filename, unsigned char**dest, int*width, int*height);
|
||||
int jpeg_load_from_mem(unsigned char*_data, int size_d, unsigned char*dest, int width, int height);
|
||||
@@ -32,9 +32,18 @@ void DeleteCriticalSection(LPCRITICAL_SECTION cs) { cs_mutex(cs).~recursive_mute
|
||||
void EnterCriticalSection(LPCRITICAL_SECTION cs) { cs_mutex(cs).lock(); }
|
||||
void LeaveCriticalSection(LPCRITICAL_SECTION cs) { cs_mutex(cs).unlock(); }
|
||||
|
||||
// Win32 takes '\\' and '/' as separators alike.
|
||||
static std::string native_path(const char* path)
|
||||
{
|
||||
std::string normalized(path ? path : "");
|
||||
for (char& ch : normalized)
|
||||
if (ch == '\\') ch = '/';
|
||||
return normalized;
|
||||
}
|
||||
|
||||
BOOL CreateDirectory(LPCSTR path, void*)
|
||||
{
|
||||
return mkdir(path, 0777) == 0 ? TRUE : FALSE;
|
||||
return mkdir(native_path(path).c_str(), 0777) == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
BOOL DeleteFile(LPCSTR path)
|
||||
@@ -49,7 +58,7 @@ int _access(const char* path, int mode)
|
||||
m |= W_OK;
|
||||
if (mode & 4)
|
||||
m |= R_OK;
|
||||
return access(path, m);
|
||||
return access(native_path(path).c_str(), m);
|
||||
}
|
||||
|
||||
int _unlink(const char* path)
|
||||
|
||||
@@ -2,11 +2,33 @@
|
||||
// Win32 shell-folder API used only by the screenshot command in grp.
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define CSIDL_PERSONAL 0x0005
|
||||
|
||||
// CSIDL_PERSONAL ("My Documents"): $HOME/Documents where it exists (desktop), otherwise the working
|
||||
// directory, which is the writable Client directory on Android. grp.SaveScreenShot appends
|
||||
// "\\METIN2\\"; CreateDirectory and jpeg_save take '\\' as a separator like Win32 does.
|
||||
inline BOOL SHGetSpecialFolderPath(void*, char* path, int, BOOL)
|
||||
{
|
||||
if (path)
|
||||
if (!path)
|
||||
return FALSE;
|
||||
path[0] = '\0';
|
||||
struct stat st;
|
||||
const char* home = std::getenv("HOME");
|
||||
if (home && home[0])
|
||||
{
|
||||
std::snprintf(path, MAX_PATH, "%s/Documents", home);
|
||||
if (::stat(path, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
return TRUE;
|
||||
}
|
||||
if (!::getcwd(path, MAX_PATH))
|
||||
{
|
||||
path[0] = '\0';
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user