diff --git a/src/screenshot.c b/src/screenshot.c index e01fa2f3f6..f383c95d9b 100644 --- a/src/screenshot.c +++ b/src/screenshot.c @@ -18,6 +18,8 @@ * along with this program. If not, see . *****************************************************************************/ +#include +#include #include #include "addresses.h" #include "gfx.h" @@ -25,8 +27,16 @@ #include "screenshot.h" #include "strings.h" #include "window_error.h" -#include -#include + +enum { + SCREENSHOT_FORMAT_BMP, + SCREENSHOT_FORMAT_PNG +}; + +int gScreenshotFormat = SCREENSHOT_FORMAT_BMP; + +static int screenshot_dump_bmp(); +static int screenshot_dump_png(); /** * @@ -52,14 +62,14 @@ void screenshot_check() } } -static int screenshot_get_next_path(char *path) +static int screenshot_get_next_path(char *path, char *extension) { int i; for (i = 1; i < 1000; i++) { RCT2_GLOBAL(0x013CE952, uint16) = i; // Glue together path and filename - sprintf(path, "%sSCR%d.PNG", RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), i); + sprintf(path, "%sSCR%d%s", RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), i, extension); if (GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) return i; @@ -68,12 +78,141 @@ static int screenshot_get_next_path(char *path) return -1; } +int screenshot_dump() +{ + switch (gScreenshotFormat) { + case SCREENSHOT_FORMAT_BMP: + return screenshot_dump_bmp(); + case SCREENSHOT_FORMAT_PNG: + return screenshot_dump_png(); + default: + 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 screenshot_dump_bmp() +{ + 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, ".bmp")) == -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; +} + +int screenshot_dump_png() { int i, index, width, height, stride; char path[MAX_PATH] = ""; @@ -85,7 +224,7 @@ int screenshot_dump() LodePNGState state; // Get a free screenshot path - if ((index = screenshot_get_next_path(path)) == -1) + if ((index = screenshot_get_next_path(path, ".png")) == -1) return -1; @@ -114,4 +253,4 @@ int screenshot_dump() free(png); return index; -} +} \ No newline at end of file diff --git a/src/screenshot.h b/src/screenshot.h index 2515ebe79d..727e8a3b0d 100644 --- a/src/screenshot.h +++ b/src/screenshot.h @@ -21,6 +21,8 @@ #ifndef _SCREENSHOT_H_ #define _SCREENSHOT_H_ +extern int gScreenshotFormat; + void screenshot_check(); int screenshot_dump();