From 2537707eaf83984bcc2550ad6b7799c53597b100 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 21 Dec 2019 13:50:22 +0100 Subject: [PATCH] Implement saving of GraphOS pictures. --- src/cpcformats.c | 88 +++++++++++++++++++++++++++++++++++++++-------- src/fileformats.h | 1 + src/libraw2crtc.c | 1 + src/loadsave.c | 2 +- src/oldies.c | 7 +++- 5 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/cpcformats.c b/src/cpcformats.c index cb989fb5..145a562f 100644 --- a/src/cpcformats.c +++ b/src/cpcformats.c @@ -7,7 +7,7 @@ Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet - Copyright 2007-2011 Adrien Destugues + Copyright 2007-2019 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or @@ -41,16 +41,23 @@ /** * Test for SCR file (Amstrad CPC) * - * SCR file format is from "Advanced OCP Art Studio" : + * SCR file format is originally from "Advanced OCP Art Studio" : * http://www.cpcwiki.eu/index.php/Format:Advanced_OCP_Art_Studio_File_Formats * * .WIN "window" format is also supported. * - * For now we check the presence of a valid PAL file. - * If the PAL file is not there the pixel data may still be valid. - * The file size depends on the screen resolution. - * An AMSDOS header would be a good indication but in some cases it may not - * be there. + * SCR files are normally just a dump of the 16K of video memory. So they are + * essentially 16 kilobytes of pixel data without any header. To make things + * more fun, there is an optional compression. This all makes detection a bit + * fuzzy. However there are various things we can still check: + * + * - Presence of a valid PAL file. If the PAL file is not there the pixel data + * may still be valid. The PAL file size depends on the screen mode (number + * of colors). + * - An AMSDOS header is a good indication but in some cases it may not + * be there. + * - Some tools embed the palette and mode (and usually some kind of loader + * code) in the SCR file, we can also detect these. */ void Test_SCR(T_IO_Context * context, FILE * file) { @@ -131,14 +138,13 @@ void Test_SCR(T_IO_Context * context, FILE * file) /** * Load Advanced OCP Art Studio files (Amstrad CPC) * - * Only standard resolution files (Mode 0 160x200, mode 1 320x200 and - * mode 2 640x200) are supported. The .PAL file presence is required. + * Standard resolution files (Mode 0 160x200, mode 1 320x200 and + * mode 2 640x200) are supported. The .PAL file is loaded if available. * "MJH" RLE packing is supported. + * Embedded CRTC registers and palette data from various tools is also + * supported. * - * .WIN "window" format is also supported. - * - * @todo Ask user for screen size (or register values) in order to support - * non standard resolutions. + * .WIN "window" format is also loaded here and allows different picture sizes. */ void Load_SCR(T_IO_Context * context) { @@ -665,7 +671,8 @@ void Save_SCR(T_IO_Context * context) * .KIT hold the palette in "Kit4096" format. There are 16 colors each stored * as 12 bit RGB in RB0G order. * .GO1 and GO2 hold each half of the picture (top and bottom) - * The file always cover the whole display of the Plus (196*272 or so) + * The file always cover the whole display of the Plus (192*272 mode 0 pixels) + * Only mode 0 is possible. */ void Test_GOS(T_IO_Context * context, FILE * file) { @@ -778,6 +785,13 @@ void Load_GOS(T_IO_Context* context) file = Open_file_read_with_alternate_ext(context, "KIT"); if (file == NULL) { // There is no palette, but that's fine, we can still load the pixels + // Setup a default grayscale palette + for (i = 0; i < 16; i++) + { + context->Palette[i].R = i * 0x11; + context->Palette[i].G = i * 0x11; + context->Palette[i].B = i * 0x11; + } return; } @@ -827,6 +841,52 @@ void Load_GOS(T_IO_Context* context) fclose(file); } + +void Save_GOS(T_IO_Context* context) +{ + FILE* file; + unsigned char* output; + unsigned long outsize = 0; + unsigned char r1 = 0; + + // TODO save KIT file for color palette + + // TODO check picture dimensions (GOS is a fixed resolution format) + // For now, force the size + context->Width = 192; + context->Height = 168; // Convert the first half + + // convert and save page 1 + output = raw2crtc(context, 0, 7, &outsize, &r1, 0, 0); + file = Open_file_write(context); + if (file == NULL) + return; + File_error = 0; + if (!Write_bytes(file, output, outsize)) + File_error = 1; + // Pad to expected size + if (!Write_bytes(file, output, 16384 - outsize)) + File_error = 1; + fclose(file); + + // convert and save page 2 + // Advance context to second half of picture + context->Target_address += context->Pitch * 168; + context->Height = 104; + output = raw2crtc(context, 0, 7, &outsize, &r1, 0, 0); + file = Open_file_write_with_alternate_ext(context, "GO2"); + if (file == NULL) + return; + File_error = 0; + if (!Write_bytes(file, output, outsize)) + File_error = 1; + // Pad to expected size + if (!Write_bytes(file, output, 16384 - outsize)) + File_error = 1; + fclose(file); +} + + /** * Test for CM5 - Amstrad CPC "Mode 5" picture * diff --git a/src/fileformats.h b/src/fileformats.h index c9808339..b1507074 100644 --- a/src/fileformats.h +++ b/src/fileformats.h @@ -141,6 +141,7 @@ void Save_PPH(T_IO_Context *); // -- Graphos (Amstrad CPC) void Test_GOS(T_IO_Context *, FILE *); void Load_GOS(T_IO_Context *); +void Save_GOS(T_IO_Context *); // -- XPM (X PixMap) // Loading is done through SDL_Image diff --git a/src/libraw2crtc.c b/src/libraw2crtc.c index 968e6ae8..5711cb47 100644 --- a/src/libraw2crtc.c +++ b/src/libraw2crtc.c @@ -179,6 +179,7 @@ unsigned char *raw2crtc(T_IO_Context *context, unsigned char mode, unsigned char } } + GFX2_Log(GFX2_DEBUG, "raw2crtc() minaddr=%x maxaddr=%x\n", minAddr, maxAddr); *outSize = (maxAddr + 1) - minAddr; outBuffer = (unsigned char*)malloc((*outSize)); diff --git a/src/loadsave.c b/src/loadsave.c index c8c3fe97..fdce7d3d 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -151,7 +151,7 @@ const T_Format File_formats[] = { {FORMAT_SCR, " cpc", Test_SCR, Load_SCR, Save_SCR, 0, 0, 0, "scr", "cpc;scr;win"}, {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, Save_CM5, 0, 0, 1, "cm5", "cm5"}, {FORMAT_PPH, " pph", Test_PPH, Load_PPH, Save_PPH, 0, 0, 1, "pph", "pph"}, - {FORMAT_GOS, " go1", Test_GOS, Load_GOS, NULL , 0, 0, 0, "go1", "go1"}, + {FORMAT_GOS, " go1", Test_GOS, Load_GOS, Save_GOS, 0, 0, 0, "go1", "go1"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_ICO, " ico", Test_ICO, Load_ICO, Save_ICO, 0, 0, 0, "ico", "ico;ic2;cur"}, {FORMAT_INFO," info",Test_INFO,Load_INFO,NULL, 0, 0, 0, "info", "info"}, diff --git a/src/oldies.c b/src/oldies.c index 83b764bf..d7f34d16 100644 --- a/src/oldies.c +++ b/src/oldies.c @@ -742,12 +742,17 @@ int CPC_check_AMSDOS(FILE * file, word * loading_address, unsigned long * file_l fseek(file, 0, SEEK_SET); if (!Read_bytes(file, data, 128)) return 0; + + // Rewind the file so it can be read normally + fseek(file, 0, SEEK_SET); for (i = 1; i <= 11; i++) // check filename and extension { if (data[i] >= 0x10 && data[i] <= 0x19) // sometimes digits are stored as 0x10 to 0x19 continue; - if (data[i] < ' ' || data[i] >= 0x7F) + if (data[i] < ' ' || data[i] >= 0x7F) { + GFX2_Log(GFX2_DEBUG, "Not an AMSDOS file: name is invalid\n"); return 0; + } } for (i = 0; i < 67; i++) checksum += (word)data[i];