From 7c24e9a9b02b04dcaf9507acb94091ea70a2c02d Mon Sep 17 00:00:00 2001 From: Xavi Del Campo Date: Fri, 31 Jan 2020 10:32:23 +0100 Subject: Imported pristine psxsdk-20190410 from official repo --- tools/tim2bmp.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 tools/tim2bmp.c (limited to 'tools/tim2bmp.c') diff --git a/tools/tim2bmp.c b/tools/tim2bmp.c new file mode 100644 index 0000000..ccb0c99 --- /dev/null +++ b/tools/tim2bmp.c @@ -0,0 +1,390 @@ +/* + * TIM2BMP + * Converts TIM, emulator save state VRAM data and raw PSX data + * to Windows bitmap format + * + * Written by Giuseppe Gatta (a.k.a. nextvolume), part of PSXSDK + */ + +#include +#include +#include +#include + +#define PCSX_1_5_SAVESTATE_SUPPORT + +z_stream strm; +unsigned short *tim_clut; + +typedef struct +{ + unsigned int clut_off; + unsigned int data_off; + unsigned short w; // Width in 16-bit unit pixels + unsigned short real_w; // Real width in pixels + unsigned short h; + unsigned char bpp; + unsigned char compr; // Compression - 0 = normal, 1 = GZIP + unsigned char has_clut; + unsigned short *clut; +}tim2bmp_info; + +tim2bmp_info tim_info; + +#include "endian.c" + +int mpink_flag = 0; + +void rgbpsx_to_rgb24(unsigned short psx_c, unsigned char *r, + unsigned char *g, unsigned char *b) +{ + *r = (psx_c & 31) << 3; + *g = ((psx_c >> 5)&31) << 3; + *b = ((psx_c >> 10) &31) << 3; + + if(mpink_flag && !(psx_c & 0x8000) && *r == 0 && *g == 0 && *b == 0) + { + *r = 255; + *g = 0; + *b = 255; + } +} + +// Returns number of bytes to round image row with. +int write_bitmap_headers(FILE *f, int w, int h, int bpp) +{ + int x; + int r; + int ret; + + if(bpp == 16) + bpp = 24; + + fputc('B', f); + fputc('M', f); + + // Calculate and write size of bitmap + + if(bpp == 24) + r = w * 3; + else if(bpp == 8) + r = w; + else if(bpp == 4) + r = w / 2; + + ret = r; + + if(r & 3) + { + r|=3; + r++; + } + + ret = r-ret; + + x=r*h; + x+=54; + + if(bpp == 8) + x+= 1024; + else if(bpp == 4) + x+= 64; + + write_le_dword(f, x); + + // Write bfReserved1 and bfReserved2 as zero + write_le_dword(f, 0); + + // Calculate and write data offset in file + + x = 54; + + if(bpp == 8) + x+= 1024; + else if(bpp == 4) + x+= 64; + + write_le_dword(f, x); + + write_le_dword(f, 40); + write_le_dword(f, w); // Width + write_le_dword(f, h); // Height + write_le_word(f, 1); + write_le_word(f, bpp); // Bits Per Pixel + write_le_dword(f, 0); + write_le_dword(f, r * h); // Image data size + write_le_dword(f, 0); + write_le_dword(f, 0); + write_le_dword(f, 0); + write_le_dword(f,0); + + return ret; +} + +int tim2bmp_read_tim(char *ip, tim2bmp_info *t) +{ + int tim_pmode; + //int tim_w, tim_h; + int /* tim_x, tim_y, tim_cx, tim_cy, */ tim_cw, tim_ch; + //int bl; + int x; + FILE *i = fopen(ip, "rb"); + + fseek(i,0,SEEK_SET); + + if(read_le_dword(i) != 0x10) + { + fclose(i); + return -1; + } + + tim_pmode = read_le_dword(i); + t->has_clut = (tim_pmode & 8) ? 1 : 0; + tim_pmode &= 7; + + if(tim_pmode == 0) t->bpp = 4; + else if(tim_pmode == 1) t->bpp = 8; + else if(tim_pmode == 2) t->bpp = 16; + else if(tim_pmode == 3) t->bpp = 24; + + if(t->has_clut) + { + t->clut_off = 8; + /* bl = */ read_le_dword(i); + /* tim_cx = */ read_le_word(i); + /* tim_cy = */ read_le_word(i); + tim_cw = read_le_word(i); + tim_ch = read_le_word(i); + + t->clut = malloc((tim_cw * tim_ch) * sizeof(short)); + + for(x = 0; x < (tim_cw * tim_ch); x++) + t->clut[x] = read_le_word(i); + } + + /* bl = */ read_le_dword(i); + + // Read framebuffer X,Y coordinates + + /* tim_x = */ read_le_word(i); + /* tim_y = */ read_le_word(i); + + // Read width and height + t->w = read_le_word(i); // Fix this for 4bpp and 8bpp images ! + t->h = read_le_word(i); + + switch(tim_pmode) + { + case 0: t->real_w = t->w * 4; break; + case 1: t->real_w = t->w * 2; break; + case 2: + t->real_w = t->w; + break; + } + + t->data_off = ftell(i); + t->compr = 0; + + fclose(i); + + return 1; +} + +int tim2bmp_read_pcsx15(char *ip, tim2bmp_info *t) +{ + t->w = 1024; + t->real_w = 1024; + t->h = 512; + t->bpp = 16; + t->has_clut = 0; + t->clut_off = 0; + t->data_off = 0x2996C0; + t->compr = 1; + + return 1; +} + +void tim2bmp_convert_image_data(char *ip, char *fp, tim2bmp_info *t) +{ + int row_round; + int y,x; + //int z; + int tim_row_off; + unsigned short c; + unsigned char r, g, b; + gzFile gzf; + //unsigned char test[17]; + FILE *i = fopen(ip, "rb"); + FILE *f = fopen(fp, "wb"); + + if(t->compr == 1) + gzf = gzopen(ip, "rb"); + + write_bitmap_headers(f, t->real_w, t->h, t->bpp); + + if(t->has_clut) + { + if(t->bpp == 4) // 4bpp + { + for(x = 0; x < 16; x++) + { + rgbpsx_to_rgb24(t->clut[x], &r, &g, &b); + fputc(b, f); + fputc(g, f); + fputc(r, f); + fputc(0, f); + } + } + else if(t->bpp == 8) // 8 bpp + { + for(x = 0; x < 256; x++) + { + rgbpsx_to_rgb24(t->clut[x], &r, &g, &b); + fputc(b, f); + fputc(g, f); + fputc(r, f); + fputc(0, f); + } + } + } + else + { + if(t->bpp == 4) fseek(f, 64, SEEK_CUR); + else if(t->bpp == 8) fseek(f, 1024, SEEK_CUR); + } + + if(t->bpp == 16) + y = (t->real_w * 24) / 8; + else + y = (t->real_w * t->bpp) / 8; + +// printf("y = %d\n", y); + row_round = y; +// printf("row_round = %d\n", y); + + if(row_round & 3) + { + row_round |= 3; + row_round++; + } +// printf("row_round = %d\n", y); + + row_round -= y; +// printf("row_round = %d\n", row_round); + + for(y = 0; y < t->h; y++) + { + tim_row_off = (t->w * 2) * ((t->h - 1)-y); + + if(t->compr == 1) + gzseek(gzf, t->data_off + tim_row_off, SEEK_SET); + else + fseek(i, t->data_off + tim_row_off, SEEK_SET); + + // printf("ERRNO SHY = %s\n", gzerror(gzf, &x)); + + + for(x = 0; x < t->w; x++) + { + if(t->compr == 1) + { + gzread(gzf, &b, 1); + c = b; + gzread(gzf, &b, 1); + c|=b<<8; + } + else + c = read_le_word(i); + + switch(t->bpp) + { + case 4: + fputc(((c >> 4) & 0xf) | ((c & 0xf) << 4), f); + fputc(((c >> 12) & 0xf) | (((c>>8)&0xf)<<4), f); + break; + case 8: + write_le_word(f, c); + break; + case 16: + rgbpsx_to_rgb24(c, &r, &g, &b); + + fputc(b, f); + fputc(g, f); + fputc(r, f); + break; + } + } + + for(x = 0; x < row_round; x++) + fputc(0, f); + } + + fclose(i); + fclose(f); + if(t->compr == 1) gzclose(gzf); +} + +int main(int argc, char *argv[]) +{ + //int x, y; + int x; + FILE *i; + //int bl; + /*int tim_w, tim_h, tim_x, tim_y, tim_cx, tim_cy, tim_cw, tim_ch; + int row_round; + unsigned short c;*/ + //unsigned char r, g, b; + /*int tim_pdata_fpos; + int tim_row_off; + int tim_pmode; + int tim_has_clut; + int actual_w; + int bmp_bpp;*/ + int r; + tim2bmp_info *t = &tim_info; + + if(argc < 2) + { + printf("tim2bmp - converts a TIM image to a bitmap\n"); + printf("usage: tim2bmp [options]\n"); + printf("\n"); + printf("Options:\n"); + printf(" -o=\n"); + printf(" -mpink - Convert transparency to magic pink\n"); + printf("\n"); + return -1; + } + + /*strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + r = deflateInit(&strm, 1);*/ + //printf("r = %d, Z_OK = %d\n", r, Z_OK); + + for(x = 3; x < argc; x++) + { + if(strcmp(argv[x], "-mpink") == 0) + mpink_flag = 1; + } + + i = fopen(argv[1], "rb"); + + if(i == NULL) + { + printf("Couldn't open specified TIM file for reading.\n"); + return -1; + } + + fclose(i); + + r = tim2bmp_read_tim(argv[1], &tim_info); + + if(r != 1) + r = tim2bmp_read_pcsx15(argv[1], &tim_info); + + if(argc > 2) + tim2bmp_convert_image_data(argv[1], argv[2], t); + + return 0; +} -- cgit v1.2.3