From 682e1a77ad9e5525f766c02889adf433341f7a8f Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Sat, 27 Apr 2019 01:57:47 +0200 Subject: [PATCH] Add support for loading the C64 pixcen .GPX format Pixcen is a C64 picture editor under MS Windows : http://hammarberg.github.io/pixcen/ --- src/const.h | 1 + src/fileformats.h | 4 + src/loadsave.c | 2 + src/miscfileformats.c | 180 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+) diff --git a/src/const.h b/src/const.h index 16ff57e0..30ac38aa 100644 --- a/src/const.h +++ b/src/const.h @@ -141,6 +141,7 @@ enum FILE_FORMATS FORMAT_CEL, ///< Atari ST Cyber Paint Cell FORMAT_NEO, ///< Atari ST NeoChrome FORMAT_C64, ///< Several C64 formats : Koala, FLI, BML, etc. + FORMAT_GPX, ///< pixcen C64 format : .gpx FORMAT_KCF, ///< KiSS Color File FORMAT_PAL, ///< raw 6bit palette or Jasc Paint Shop Pro palette FORMAT_GPL, ///< Gimp palette diff --git a/src/fileformats.h b/src/fileformats.h index a5e11f5a..ab401728 100644 --- a/src/fileformats.h +++ b/src/fileformats.h @@ -111,6 +111,10 @@ void Test_C64(T_IO_Context *, FILE *); void Load_C64(T_IO_Context *); void Save_C64(T_IO_Context *); +// -- GPX (pixcen C64) +void Test_GPX(T_IO_Context *, FILE *); +void Load_GPX(T_IO_Context *); + // -- SCR (Amstrad CPC) void Test_SCR(T_IO_Context *, FILE *); void Load_SCR(T_IO_Context *); diff --git a/src/loadsave.c b/src/loadsave.c index ac82593e..cd7124a7 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -115,6 +115,7 @@ const T_Format File_formats[] = { "gif;png;bmp;2bp;pcx;pkm;iff;lbm;ilbm;sham;ham;ham6;ham8;acbm;pic;anim;img;sci;scq;scf;scn;sco;cel;" "pi1;pc1;pi2;pc2;pi3;pc3;neo;" "c64;p64;a64;pi;rp;aas;art;dd;iph;ipt;hpc;ocp;koa;koala;fli;bml;cdu;prg;pmg;rpm;" + "gpx;" "cpc;scr;win;" "hgr;dhgr;" "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;ic2;cur;cm5;pph;info;flc;bin;map"}, @@ -141,6 +142,7 @@ const T_Format File_formats[] = { {FORMAT_GPL, " gpl", Test_GPL, Load_GPL, Save_GPL, 1, 0, 0, "gpl", "gpl"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 1, "c64", "c64;p64;a64;pi;rp;aas;art;dd;iph;ipt;hpc;ocp;koa;koala;fli;bml;cdu;prg;pmg;rpm"}, + {FORMAT_GPX, " gpx", Test_GPX, Load_GPX, NULL, 0, 0, 0, "gpx", "gpx"}, {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"}, diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 32045792..e027175b 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -38,6 +38,8 @@ #endif #endif +#include + #include "engine.h" #include "errors.h" #include "global.h" @@ -4034,6 +4036,184 @@ void Save_C64(T_IO_Context * context) } +/////////////////////////// pixcen *.GPX /////////////////////////// +void Test_GPX(T_IO_Context * context, FILE * file) +{ + byte header[2]; + (void)context; + + // check for a Zlib compressed stream + File_error = 1; + if (!Read_bytes(file, header, 2)) + return; + if ((header[0] & 0x0f) != 8) + return; + if (((header[0] << 8) + header[1]) % 31) + return; + File_error = 0; +} + +void Load_GPX(T_IO_Context * context) +{ + FILE * file; + unsigned long file_size; + byte * buffer; + + File_error = 1; + file = Open_file_read(context); + if (file == NULL) + return; + file_size = File_length_file(file); + buffer = malloc(file_size); + if (buffer == NULL) + { + GFX2_Log(GFX2_ERROR, "Failed to allocate %lu bytes.\n", file_size); + fclose(file); + return; + } + if (Read_bytes(file, buffer, file_size)) + { + byte * gpx = NULL; + unsigned long gpx_size = 0; + int r; + + do + { + free(gpx); + gpx_size += 65536; + gpx = malloc(gpx_size); + if (gpx == NULL) + { + GFX2_Log(GFX2_ERROR, "Failed to allocate %lu bytes\n", gpx_size); + break; + } + r = uncompress(gpx, &gpx_size, buffer, file_size); + if (r != Z_BUF_ERROR && r != Z_OK) + GFX2_Log(GFX2_ERROR, "uncompress() failed with error %d: %s\n", r, zError(r)); + } + while (r == Z_BUF_ERROR); // there was not enough room in the output buffer + if (r == Z_OK) + { + byte * p; + dword version, mode; +/* + mode : +0 BITMAP, +1 MC_BITMAP, +2 SPRITE, +3 MC_SPRITE, +4 CHAR, +5 MC_CHAR, +6 UNUSED1, +7 UNUSED2, +8 UNRESTRICTED, +9 W_UNRESTRICTED +*/ + GFX2_Log(GFX2_DEBUG, "inflated %lu bytes to %lu\n", file_size, gpx_size); +#define READU32LE(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24) + version = READU32LE(gpx); + mode = READU32LE(gpx+4); + GFX2_Log(GFX2_DEBUG, "gpx version %u mode %u\n", version, mode); + snprintf(context->Comment, COMMENT_SIZE, "pixcen file version %u mode %u", version, mode); + if (version >= 4) + { + dword count; + const char * key; + word value[256]; + int xsize = -1; + int ysize = -1; + int mapsize = -1; + int screensize = -1; + int colorsize = -1; + int backbuffers = -1; + + count = READU32LE(gpx+8); + p = gpx + 12; + while (count--) + { + int i = 0; + int int_value = 0; + + key = (const char *)p; + while (*p++); + for (;;) + { + value[i] = p[0] + (p[1] << 8); + p += 2; + if (value[i] == 0) + break; + int_value = int_value * 10 + (value[i] - '0'); + i++; + } + GFX2_Log(GFX2_DEBUG, "%s=%d\n", key, int_value); + if (0 == strcmp(key, "xsize")) + xsize = int_value; + else if (0 == strcmp(key, "ysize")) + ysize = int_value; + else if (0 == strcmp(key, "mapsize")) + mapsize = int_value; + else if (0 == strcmp(key, "screensize")) + screensize = int_value; + else if (0 == strcmp(key, "colorsize")) + colorsize = int_value; + else if (0 == strcmp(key, "backbuffers")) + backbuffers = int_value; + } +//buffersize = 64 + (64 + mapsize + screensize + colorsize) * backbuffers; + p += 64; // 64 empty bytes ? + File_error = 0; + if (mode & 1) + context->Ratio = PIXEL_WIDE; + else + context->Ratio = PIXEL_SIMPLE; + Pre_load(context, xsize, ysize, file_size, FORMAT_GPX, context->Ratio, 4); // Do this as soon as you can + if (Config.Clear_palette) + memset(context->Palette,0, sizeof(T_Palette)); + C64_set_palette(context->Palette); + context->Transparent_color=16; + + //foreach backbuffer + if (backbuffers >= 1) + { + byte border, background; + //byte ext0, ext1, ext2; + byte * bitmap, * color, * screen; + + //GFX2_LogHexDump(GFX2_DEBUG, "GPX ", p, 0, 64); + p += 47; // Extra bytes + //crippled = p; + p += 6; + //lock = p; + p += 6; + border = *p++; + background = *p++; + /*ext0 = *p++; + ext1 = *p++; + ext2 = *p++;*/ + p += 3; + bitmap = p; + p += mapsize; + color = p; + p += colorsize; + screen = p; + p += screensize; + + (void)border; + Load_C64_multi(context, bitmap, screen, color, background); + Set_image_mode(context, (mode & 1) ? IMAGE_MODE_C64MULTI : IMAGE_MODE_C64HIRES); + } + } + else + { + GFX2_Log(GFX2_ERROR, "GPX file version %d unsupported\n", version); + } + } + free(gpx); + } + free(buffer); + fclose(file); +} + /** * Test for SCR file (Amstrad CPC) *