From 218cd32c7dc9512ace700de073d00837347f1948 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Sat, 26 Apr 2014 03:17:32 +0100 Subject: [PATCH] add bitmap screenshot saving --- src/gfx.h | 2 +- src/screenshot.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/gfx.h b/src/gfx.h index 1280468be3..47ef36c70a 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -30,7 +30,7 @@ typedef struct { short y; // 0x06 short width; // 0x08 short height; // 0x0A - short pitch; // 0x0C + short pitch; // 0x0C note: this is actually (pitch - width) char pad_0E; // 0x0E char var_0F; // 0x0F } rct_drawpixelinfo; diff --git a/src/screenshot.c b/src/screenshot.c index a6cd27d281..93d7b181bc 100644 --- a/src/screenshot.c +++ b/src/screenshot.c @@ -18,7 +18,9 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "addresses.h" +#include "gfx.h" #include "rct2.h" #include "screenshot.h" #include "strings.h" @@ -48,13 +50,143 @@ void screenshot_check() } } +static int screenshot_get_next_path(char *path) +{ + char *placeHolder; + + strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char)); + placeHolder = path + strlen(path); + + int i; + for (i = 1; i < 1000; i++) { + RCT2_GLOBAL(0x013CE952, uint16) = i; + format_string(placeHolder, STR_SCR_BMP, 0x013CE952); + + if (GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) + return i; + } + + return -1; +} + +// Bitmap header structs, for cross platform purposes +typedef struct { + uint16 bfType; + uint32 bfSize; + uint16 bfReserved1; + uint16 bfReserved2; + uint32 bfOffBits; +} BitmapFileHeader; + +typedef struct { + uint32 biSize; + sint32 biWidth; + sint32 biHeight; + uint16 biPlanes; + uint16 biBitCount; + uint32 biCompression; + uint32 biSizeImage; + sint32 biXPelsPerMeter; + sint32 biYPelsPerMeter; + uint32 biClrUsed; + uint32 biClrImportant; +} BitmapInfoHeader; + /** * * rct2: 0x00683D20 */ int screenshot_dump() { - int eax, ebx, ecx, edx, esi, edi, ebp; - RCT2_CALLFUNC_X(0x00683D20, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return eax & 0xFFFF; + BitmapFileHeader header; + BitmapInfoHeader info; + + int i, x, y, index, width, height, stride; + char *buffer, path[MAX_PATH], *row, *dst; + HFILE hFile; + DWORD bytesWritten; + + // Get a free screenshot path + if ((index = screenshot_get_next_path(path)) == -1) + return -1; + + // Open file for writing + hFile = CreateFile(path, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + + // Allocate buffer + buffer = malloc(0xFFFF); + if (buffer == NULL) { + CloseHandle(hFile); + return -1; + } + + // Get image size + width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); + stride = (width + 3) & 0xFFFFFFFC; + + // File header + memset(&header, 0, sizeof(header)); + header.bfType = 0x4D42; + header.bfSize = height * stride + 1038; + header.bfOffBits = 1038; + + WriteFile(hFile, &header, sizeof(header), &bytesWritten, NULL); + if (bytesWritten != sizeof(header)) { + CloseHandle(hFile); + free(buffer); + } + + // Info header + memset(&info, 0, sizeof(info)); + info.biSize = sizeof(info); + info.biWidth = width; + info.biHeight = height; + info.biPlanes = 1; + info.biBitCount = 8; + info.biXPelsPerMeter = 2520; + info.biYPelsPerMeter = 2520; + info.biClrUsed = 246; + + WriteFile(hFile, &info, sizeof(info), &bytesWritten, NULL); + if (bytesWritten != sizeof(info)) { + CloseHandle(hFile); + free(buffer); + } + + // Palette + memset(buffer, 0, 246 * 4); + for (i = 0; i < 246; i++) { + buffer[i * 4 + 0] = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 0]; + buffer[i * 4 + 1] = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 1]; + buffer[i * 4 + 2] = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 2]; + } + + WriteFile(hFile, buffer, 246 * 4, &bytesWritten, NULL); + if (bytesWritten != 246 * 4) { + CloseHandle(hFile); + free(buffer); + } + + // Image, save upside down + rct_drawpixelinfo *dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + for (y = dpi->height - 1; y >= 0; y--) { + row = dpi->bits + y * (dpi->width + dpi->pitch); + + memset(buffer, 0, stride); + memcpy(buffer, row, dpi->width); + + WriteFile(hFile, buffer, stride, &bytesWritten, NULL); + if (bytesWritten != stride) { + CloseHandle(hFile); + free(buffer); + } + } + + CloseHandle(hFile); + free(buffer); + + return index; } \ No newline at end of file