From 38b8f5f2cc7d317d6b5b44eb032b88df717fb878 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 12 May 2025 23:01:59 +0200 Subject: [PATCH] Add implementation for bitmapwrite --- src/debug/Makefile.am | 1 + src/debug/bitmap.c | 201 +++++++++++++++++++++++++++++++++++++++++ src/debug/screenshot.c | 17 +++- 3 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 src/debug/bitmap.c diff --git a/src/debug/Makefile.am b/src/debug/Makefile.am index 4ea86c5d..b7677921 100644 --- a/src/debug/Makefile.am +++ b/src/debug/Makefile.am @@ -24,6 +24,7 @@ libpspdebuginclude_HEADERS = \ lib_LIBRARIES = libpspdebug.a libpspgdb.a libpspgdb_user.a libpspgdb_kernel.a libpspdebugkb.a libpspdebug_a_SOURCES = \ + bitmap.c \ callstack.c \ callstackget.S \ font.c \ diff --git a/src/debug/bitmap.c b/src/debug/bitmap.c new file mode 100644 index 00000000..4804fcd3 --- /dev/null +++ b/src/debug/bitmap.c @@ -0,0 +1,201 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * bitmap.c - Take a screenshot and save it as a bitmap file + * + * Copyright (c) 2025, Francisco Javier Trujillo Mata + * + */ + +#include +#include +#include +#include +#include + +#define BMP_ID "BM" +#define PSP_SCREEN_WIDTH 480 +#define PSP_SCREEN_HEIGHT 272 +#define PSP_LINE_SIZE 512 +#define BMP_RGB_BYTES_PER_PIXEL 3 // BMP format uses 24-bit RGB (3 bytes per pixel) + +// Helper function to get pixel depth in bytes for a given format +static int get_pixel_depth(int format) +{ + switch (format) + { + case PSP_DISPLAY_PIXEL_FORMAT_565: + case PSP_DISPLAY_PIXEL_FORMAT_5551: + case PSP_DISPLAY_PIXEL_FORMAT_4444: + return 2; // 16-bit formats + case PSP_DISPLAY_PIXEL_FORMAT_8888: + return 4; // 32-bit format + default: + return 0; // Invalid format + } +} + +struct BitmapHeader +{ + char id[2]; + uint32_t filesize; + uint32_t reserved; + uint32_t offset; + uint32_t headsize; + uint32_t width; + uint32_t height; + uint16_t planes; + uint16_t bpp; + uint32_t comp; + uint32_t bitmapsize; + uint32_t hres; + uint32_t vres; + uint32_t colors; + uint32_t impcolors; +} __attribute__((packed)); + +static int fixed_write(int fd, void *data, int len) +{ + int writelen = 0; + + while (writelen < len) + { + int ret; + + ret = sceIoWrite(fd, data + writelen, len - writelen); + if (ret <= 0) + { + writelen = -1; + break; + } + writelen += ret; + } + + return writelen; +} + +void write_8888_line(void *frame, void *line_buf, int line) +{ + uint8_t *line_data = line_buf; + const int pixel_depth = get_pixel_depth(PSP_DISPLAY_PIXEL_FORMAT_8888); + uint8_t *p = frame + (line * PSP_LINE_SIZE * pixel_depth); + int i; + + for (i = 0; i < PSP_SCREEN_WIDTH; i++) + { + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 2] = p[i * pixel_depth]; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 1] = p[(i * pixel_depth) + 1]; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 0] = p[(i * pixel_depth) + 2]; + } +} + +void write_5551_line(void *frame, void *line_buf, int line) +{ + uint8_t *line_data = line_buf; + const int pixel_depth = get_pixel_depth(PSP_DISPLAY_PIXEL_FORMAT_5551); + uint16_t *p = frame + (line * PSP_LINE_SIZE * pixel_depth); + int i; + + for (i = 0; i < PSP_SCREEN_WIDTH; i++) + { + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 2] = (p[i] & 0x1F) << 3; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 1] = ((p[i] >> 5) & 0x1F) << 3; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 0] = ((p[i] >> 10) & 0x1F) << 3; + } +} + +void write_565_line(void *frame, void *line_buf, int line) +{ + uint8_t *line_data = line_buf; + const int pixel_depth = get_pixel_depth(PSP_DISPLAY_PIXEL_FORMAT_565); + uint16_t *p = frame + (line * PSP_LINE_SIZE * pixel_depth); + int i; + + for (i = 0; i < PSP_SCREEN_WIDTH; i++) + { + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 2] = (p[i] & 0x1F) << 3; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 1] = ((p[i] >> 5) & 0x3F) << 2; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 0] = ((p[i] >> 11) & 0x1F) << 3; + } +} + +void write_4444_line(void *frame, void *line_buf, int line) +{ + uint8_t *line_data = line_buf; + const int pixel_depth = get_pixel_depth(PSP_DISPLAY_PIXEL_FORMAT_4444); + uint16_t *p = frame + (line * PSP_LINE_SIZE * pixel_depth); + int i; + + for (i = 0; i < PSP_SCREEN_WIDTH; i++) + { + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 2] = (p[i] & 0xF) << 4; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 1] = ((p[i] >> 4) & 0xF) << 4; + line_data[(i * BMP_RGB_BYTES_PER_PIXEL) + 0] = ((p[i] >> 8) & 0xF) << 4; + } +} + +int bitmapWrite(void *frame_addr, int format, const char *file) +{ + struct BitmapHeader bmp; + uint8_t line_buf[PSP_SCREEN_WIDTH * BMP_RGB_BYTES_PER_PIXEL]; // Stack buffer for one line of RGB data + int fd; + int line; + + // Initialize header + memset(&bmp, 0, sizeof(struct BitmapHeader)); + memcpy(bmp.id, BMP_ID, sizeof(bmp.id)); + bmp.filesize = PSP_SCREEN_WIDTH * PSP_SCREEN_HEIGHT * BMP_RGB_BYTES_PER_PIXEL + sizeof(struct BitmapHeader); + bmp.offset = sizeof(struct BitmapHeader); + bmp.headsize = 0x28; + bmp.width = PSP_SCREEN_WIDTH; + bmp.height = PSP_SCREEN_HEIGHT; + bmp.planes = 1; + bmp.bpp = BMP_RGB_BYTES_PER_PIXEL * 8; // Convert bytes to bits + bmp.bitmapsize = PSP_SCREEN_WIDTH * PSP_SCREEN_HEIGHT * BMP_RGB_BYTES_PER_PIXEL; + bmp.hres = 2834; + bmp.vres = 2834; + + fd = sceIoOpen(file, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777); + if (fd < 0) + { + return -1; + } + + // Write header first + if (fixed_write(fd, &bmp, sizeof(struct BitmapHeader)) != sizeof(struct BitmapHeader)) + { + sceIoClose(fd); + return -1; + } + + // Process and write each line (from bottom to top as required by BMP format) + for (line = PSP_SCREEN_HEIGHT - 1; line >= 0; line--) + { + switch (format) + { + case PSP_DISPLAY_PIXEL_FORMAT_565: + write_565_line(frame_addr, line_buf, line); + break; + case PSP_DISPLAY_PIXEL_FORMAT_5551: + write_5551_line(frame_addr, line_buf, line); + break; + case PSP_DISPLAY_PIXEL_FORMAT_4444: + write_4444_line(frame_addr, line_buf, line); + break; + case PSP_DISPLAY_PIXEL_FORMAT_8888: + write_8888_line(frame_addr, line_buf, line); + break; + } + + if (fixed_write(fd, line_buf, sizeof(line_buf)) != sizeof(line_buf)) + { + sceIoClose(fd); + return -1; + } + } + + sceIoClose(fd); + return 0; +} diff --git a/src/debug/screenshot.c b/src/debug/screenshot.c index 0d175e6b..2857345c 100644 --- a/src/debug/screenshot.c +++ b/src/debug/screenshot.c @@ -10,8 +10,23 @@ */ #include "pspdebug.h" +#include "pspdisplay.h" +#include "pspuser.h" + +#define PSP_SCREEN_HEIGHT 272 + +int bitmapWrite(void *frame_addr, int format, const char *file); int pspScreenshotSave(const char *filename) { - return 0; + void* buff; + int bufferwidth, pixelformat; + + int ret = sceDisplayGetFrameBuf(&buff, &bufferwidth, &pixelformat, PSP_DISPLAY_SETBUF_NEXTHSYNC); + if (ret != 0 || buff == NULL || bufferwidth == 0) { + return -1; + } + + // write the screenshot to the file + return bitmapWrite(buff, pixelformat, filename); } \ No newline at end of file