win32: only load screenshots in preview dialogs

This commit is contained in:
OV2 2019-12-19 18:19:50 +01:00
parent 3c2ef2aa21
commit 04a15d9a2e
3 changed files with 91 additions and 85 deletions

View File

@ -71,88 +71,96 @@ bool CSaveLoadWithPreviewDlg::init_preview_bmps()
void CSaveLoadWithPreviewDlg::load_slot_image_text(int slot, HWND hDlg) void CSaveLoadWithPreviewDlg::load_slot_image_text(int slot, HWND hDlg)
{ {
// load the snapshot to receive the saved screenshot uint16 *image_buffer;
FreezeUnfreezeSlot(slot, FALSE); int width, height;
// create temporary bitmap storage for screenshot, 16bit RGB // load the saved screenshot from a snapshot
uint8_t* buffer = NULL; if(UnfreezeScreenshotSlot(slot, &image_buffer, width, height))
BITMAPINFO *bm = (BITMAPINFO *)calloc(sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD), 1);
bm->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bm->bmiHeader.biWidth = IPPU.RenderedScreenWidth;
bm->bmiHeader.biHeight = -IPPU.RenderedScreenHeight; // negative is top-down
bm->bmiHeader.biPlanes = 1;
bm->bmiHeader.biBitCount = 16;
bm->bmiHeader.biCompression = BI_BITFIELDS;
bm->bmiHeader.biSizeImage = IPPU.RenderedScreenWidth * IPPU.RenderedScreenHeight * 2;
*(unsigned long *)&bm->bmiColors[0] = FIRST_COLOR_MASK_RGB565;
*(unsigned long *)&bm->bmiColors[1] = SECOND_COLOR_MASK_RGB565;
*(unsigned long *)&bm->bmiColors[2] = THIRD_COLOR_MASK_RGB565;
HBITMAP imageBmp = CreateDIBSection(NULL, bm, DIB_RGB_COLORS, (void**)&buffer, 0, 0);
if(imageBmp == NULL)
{ {
// create temporary bitmap storage for screenshot, 16bit RGB
uint8_t* buffer = NULL;
BITMAPINFO *bm = (BITMAPINFO *)calloc(sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD), 1);
bm->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bm->bmiHeader.biWidth = width;
bm->bmiHeader.biHeight = -height; // negative is top-down
bm->bmiHeader.biPlanes = 1;
bm->bmiHeader.biBitCount = 16;
bm->bmiHeader.biCompression = BI_BITFIELDS;
bm->bmiHeader.biSizeImage = width * height * 2;
*(unsigned long *)&bm->bmiColors[0] = FIRST_COLOR_MASK_RGB565;
*(unsigned long *)&bm->bmiColors[1] = SECOND_COLOR_MASK_RGB565;
*(unsigned long *)&bm->bmiColors[2] = THIRD_COLOR_MASK_RGB565;
HBITMAP imageBmp = CreateDIBSection(NULL, bm, DIB_RGB_COLORS, (void**)&buffer, 0, 0);
if(imageBmp == NULL)
{
free(bm);
return;
}
int row_bytes = width * 2 / 4 * 4; // DIBs always have 4-byte aligned rows
if(width * 2 % 4)
row_bytes += 4;
// copy saved screenshot into temporary bitmap
uint16 *screen = image_buffer;
for(int h = 0; h < height; h++, screen += width)
{
uint16_t *row_start = (uint16_t*)(buffer + (h * row_bytes));
for(int w = 0; w < width; w++)
{
row_start[w] = screen[w];
}
}
// strech temporary bitmap into HBIMAP for button
HDC cdc = CreateCompatibleDC(GetDC(NULL));
HGDIOBJ old = SelectObject(cdc, previewHbmps[slot]);
int ret = StretchDIBits(cdc, 0, 0, PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT, 0, 0, width, height, buffer, bm, DIB_RGB_COLORS, SRCCOPY);
SelectObject(cdc, old);
DeleteDC(cdc);
free(bm); free(bm);
return;
}
int row_bytes = IPPU.RenderedScreenWidth * 2 / 4 * 4; // DIBs always have 4-byte aligned rows // set image to button
if(IPPU.RenderedScreenWidth * 2 % 4) SendMessage(GetDlgItem(hDlg, IDC_BUTTON_SLOT_1 + slot), BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)previewHbmps[slot]);
row_bytes += 4;
// copy saved screenshot into temporary bitmap char filename[_MAX_PATH + 1];
uint16 *screen = GFX.Screen; GetSlotFilename(slot, filename);
for(int h = 0; h < IPPU.RenderedScreenHeight; h++, screen += GFX.RealPPL) Utf8ToWide filenameW(filename);
{
uint16_t *row_start = (uint16_t*)(buffer + (h * row_bytes)); // text with filename and last write time
for(int w = 0; w < IPPU.RenderedScreenWidth; w++) std::wstring static_text(PathFindFileName(filenameW));
// get file time details
HANDLE file_handle = CreateFile(filenameW, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(file_handle != INVALID_HANDLE_VALUE)
{ {
row_start[w] = screen[w]; FILETIME ft;
SYSTEMTIME stUTC, stLocal;
// transform from file time to local time
if(GetFileTime(file_handle, NULL, NULL, &ft) &&
FileTimeToSystemTime(&ft, &stUTC) &&
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal))
{
// reserve space for date and time (both received individually)
std::vector<wchar_t> date_string;
date_string.resize(max(
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_AUTOLAYOUT | DATE_LONGDATE, &stLocal, NULL, NULL, 0, NULL),
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &stLocal, NULL, NULL, 0)
));
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_AUTOLAYOUT | DATE_LONGDATE, &stLocal, NULL, &date_string[0], 100, NULL);
static_text.append(L"\n").append(&date_string[0]);
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &stLocal, NULL, &date_string[0], 100);
static_text.append(L" ").append(&date_string[0]);
}
} }
// set the description text
SetWindowText(GetDlgItem(hDlg, IDC_STATIC_SLOT_1 + slot), static_text.c_str());
free(image_buffer);
} }
// strech temporary bitmap into HBIMAP for button
HDC cdc = CreateCompatibleDC(GetDC(NULL));
HGDIOBJ old = SelectObject(cdc, previewHbmps[slot]);
int ret = StretchDIBits(cdc, 0, 0, PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT, 0, 0, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, buffer, bm, DIB_RGB_COLORS, SRCCOPY);
SelectObject(cdc, old);
DeleteDC(cdc);
free(bm);
// set image to button
SendMessage(GetDlgItem(hDlg, IDC_BUTTON_SLOT_1 + slot), BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)previewHbmps[slot]);
// text with filename and last write time
std::wstring static_text(PathFindFileName((wchar_t*)_tFromChar(Memory.ROMFilename)));
// get file time details
char filename[_MAX_PATH + 1];
GetSlotFilename(slot, filename);
HANDLE file_handle = CreateFile(_tFromChar(filename), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(file_handle != INVALID_HANDLE_VALUE)
{
FILETIME ft;
SYSTEMTIME stUTC, stLocal;
// transform from file time to local time
if(GetFileTime(file_handle, NULL, NULL, &ft) &&
FileTimeToSystemTime(&ft, &stUTC) &&
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal))
{
// reserve space for date and time (both received individually)
std::vector<wchar_t> date_string;
date_string.resize(max(
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_AUTOLAYOUT | DATE_LONGDATE, &stLocal, NULL, NULL, 0, NULL),
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &stLocal, NULL, NULL, 0)
));
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_AUTOLAYOUT | DATE_LONGDATE, &stLocal, NULL, &date_string[0], 100, NULL);
static_text.append(L"\n").append(&date_string[0]);
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &stLocal, NULL, &date_string[0], 100);
static_text.append(L" ").append(&date_string[0]);
}
}
// set the description text
SetWindowText(GetDlgItem(hDlg, IDC_STATIC_SLOT_1 + slot), static_text.c_str());
} }
void CSaveLoadWithPreviewDlg::init_window(HWND hDlg) void CSaveLoadWithPreviewDlg::init_window(HWND hDlg)
@ -160,13 +168,6 @@ void CSaveLoadWithPreviewDlg::init_window(HWND hDlg)
if(is_save_dialog) if(is_save_dialog)
SetWindowText(hDlg, L"Save with preview"); SetWindowText(hDlg, L"Save with preview");
// we need to load snapshots to receive the preview images, so we save the current state,
// load the slots, then reload the backup
std::string backup_filename = S9xGetFilename(".preview_backup", SNAPSHOT_DIR);
// create backup
FreezeUnfreeze(backup_filename.c_str(), true);
int x_pos = 0; int x_pos = 0;
int y_pos = 0; int y_pos = 0;
for(int i = 0; i < NUM_DIALOG_SLOTS; i++) for(int i = 0; i < NUM_DIALOG_SLOTS; i++)
@ -222,10 +223,6 @@ void CSaveLoadWithPreviewDlg::init_window(HWND hDlg)
int left = (mi.rcWork.right - mi.rcWork.left - dialog_width) / 2; int left = (mi.rcWork.right - mi.rcWork.left - dialog_width) / 2;
int top = (mi.rcWork.bottom - mi.rcWork.top - dialog_height) / 2; int top = (mi.rcWork.bottom - mi.rcWork.top - dialog_height) / 2;
SetWindowPos(hDlg, NULL, left, top, dialog_width, dialog_height, SWP_NOZORDER); SetWindowPos(hDlg, NULL, left, top, dialog_width, dialog_height, SWP_NOZORDER);
// load backup, remove temporary state
FreezeUnfreeze(backup_filename.c_str(), false);
remove(backup_filename.c_str());
} }
INT_PTR CALLBACK CSaveLoadWithPreviewDlg::DlgLoadWithPreview(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) INT_PTR CALLBACK CSaveLoadWithPreviewDlg::DlgLoadWithPreview(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)

View File

@ -3703,6 +3703,14 @@ void FreezeUnfreeze (const char *filename, bool8 freeze)
S9xClearPause (PAUSE_FREEZE_FILE); S9xClearPause (PAUSE_FREEZE_FILE);
} }
bool UnfreezeScreenshotSlot(int slot, uint16 **image_buffer, int &width, int &height)
{
char filename[_MAX_PATH + 1];
GetSlotFilename(slot, filename);
return S9xUnfreezeScreenshot(filename, image_buffer, width, height);
}
void CheckDirectoryIsWritable (const char *filename) void CheckDirectoryIsWritable (const char *filename)
{ {
FILE *fs = fopen (filename, "w+"); FILE *fs = fopen (filename, "w+");

View File

@ -463,5 +463,6 @@ void GetSlotFilename(int slot, char filename[_MAX_PATH + 1]);
void FreezeUnfreezeSlot(int slot, bool8 freeze); void FreezeUnfreezeSlot(int slot, bool8 freeze);
void FreezeUnfreezeDialog(bool8 freeze); void FreezeUnfreezeDialog(bool8 freeze);
void FreezeUnfreeze(const char *filename, bool8 freeze); void FreezeUnfreeze(const char *filename, bool8 freeze);
bool UnfreezeScreenshotSlot(int slot, uint16 **image_buffer, int &width, int &height);
#endif // !defined(SNES9X_H_INCLUDED) #endif // !defined(SNES9X_H_INCLUDED)