Mercurial > hg > dmlib
view tools/lib64fmts.c @ 1763:847bd77a538d
Implement Rainbow Painter format support.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 12 Jun 2018 00:27:37 +0300 |
parents | b69f3d97db9e |
children | 52e31cfc1e36 |
line wrap: on
line source
/* * Functions for reading and converting various restricted * C64/etc and/or indexed/paletted graphics formats. * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2012-2018 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ #include "lib64gfx.h" static int fmtProbeKoalaPaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { // Attempt to prevent misprobes of unpacked Koala and Run Paint if (len > 30 && len != 10006 && len != 10003 && dmCompareAddr16(buf, 0, fmt->addr)) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } static int fmtDecodeKoalaPaintPacked(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem; DMCompParams cfg; cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_2; cfg.rleMarkerB = 0xfe; if ((res = dmDecodeGenericRLEAlloc(&mem, buf, &cfg)) != DMERR_OK) goto out; res = dmC64DecodeGenericBMP(img, &mem, fmt); out: dmGrowBufFree(&mem); return res; } static int fmtEncodeKoalaPaintPacked(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { int res; DMGrowBuf tmp; DMCompParams cfg; // Encode the data to temp buffer if ((res = dmC64EncodeGenericBMP(TRUE, &tmp, img, fmt)) != DMERR_OK) goto out; // And now RLE compress the data to the existing buffer cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_2; cfg.rleMarkerB = 0xfe; cfg.rleMinCountB = 3; cfg.rleMaxCountB = 255; res = dmEncodeGenericRLE(buf, &tmp, &cfg); out: dmGrowBufFree(&tmp); return res; } static int fmtProbeDrazPaint20Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { const Uint8 *ident = buf + 2; if (len > 22 && dmCompareAddr16(buf, 0, fmt->addr) && memcmp(ident, "DRAZPAINT ", 10) == 0 && ident[11] == '.' && ( (ident[10] == '1' && ident[12] == '4') || (ident[10] == '2' && ident[12] == '0') )) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } static int fmtDecodeDrazPaintPacked(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem, tmp; DMCompParams cfg; cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMarkerB = buf->data[0x0d]; if ((res = dmDecodeGenericRLEAlloc(&mem, dmGrowBufConstCopyOffs(&tmp, buf, 0x0e), &cfg)) != DMERR_OK) goto out; res = dmC64DecodeGenericBMP(img, &mem, fmt); out: dmGrowBufFree(&mem); return res; } static int fmtEncodeDrazPaintPacked(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { int res; DMGrowBuf tmp; DMCompParams cfg; const char *magicID = (fmt->type & D64_FMT_ILACE) ? "DRAZLACE! 1.0" : "DRAZPAINT 2.0"; // Encode the data to temp buffer if ((res = dmC64EncodeGenericBMP(TRUE, &tmp, img, fmt)) != DMERR_OK) goto out; // Analyze and setup RLE cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMinCountB = 3; cfg.rleMaxCountB = 255; dmGenericRLEAnalyze(&tmp, &cfg); // Add the header bits if (!dmGrowBufPut(buf, (Uint8 *) magicID, strlen(magicID)) || !dmGrowBufPutU8(buf, cfg.rleMarkerB)) { res = DMERR_MALLOC; goto out; } // And now RLE compress the data to the existing buffer res = dmEncodeGenericRLE(buf, &tmp, &cfg); out: dmGrowBufFree(&tmp); return res; } static int fmtProbeDrazLace10Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { if (len > 22 && dmCompareAddr16(buf, 0, fmt->addr) && memcmp(buf + 2, "DRAZLACE! 1.0", 13) == 0) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } static BOOL fmtDrazLaceGetLaceType(DMC64Image *img, const DMC64EncDecOp *op, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { (void) fmt; img->laceType = buf->data[op->offs] ? D64_ILACE_RES : D64_ILACE_COLOR; return TRUE; } static BOOL fmtDrazLaceSetLaceType(const DMC64EncDecOp *op, DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { (void) fmt; buf->data[op->offs] = (img->laceType == D64_ILACE_RES) ? 1 : 0; return TRUE; } static const char *fmtBDP5MagicID = "BDP 5.00"; static int fmtProbeBDP5Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { if (len > 20 && dmCompareAddr16(buf, 0, fmt->addr) && memcmp(buf + 2, fmtBDP5MagicID, strlen(fmtBDP5MagicID)) == 0) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } static int fmtDecodeBDP5Packed(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem, tmp; DMCompParams cfg; cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_WORD_RUNS | DM_RLE_ORDER_1; cfg.rleMarkerB = buf->data[8]; cfg.rleMarkerW = buf->data[9]; if ((res = dmDecodeGenericRLEAlloc(&mem, dmGrowBufConstCopyOffs(&tmp, buf, 10), &cfg)) != DMERR_OK) goto out; res = dmC64DecodeGenericBMP(img, &mem, fmt); out: dmGrowBufFree(&mem); return res; } static int fmtEncodeBDP5Packed(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem; DMCompParams cfg; // Encode the data to temp buffer if ((res = dmC64EncodeGenericBMP(TRUE, &mem, img, fmt)) != DMERR_OK) goto out; // Analyze and setup RLE cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_WORD_RUNS | DM_RLE_ORDER_1; cfg.rleMinCountB = 3; cfg.rleMaxCountB = 255; cfg.rleMinCountW = 256; cfg.rleMaxCountW = 1024; dmGenericRLEAnalyze(&mem, &cfg); // Add the header bits if (!dmGrowBufPut(buf, (Uint8 *) fmtBDP5MagicID, strlen(fmtBDP5MagicID)) || !dmGrowBufPutU8(buf, cfg.rleMarkerB) || !dmGrowBufPutU8(buf, cfg.rleMarkerW)) { res = DMERR_MALLOC; goto out; } // And now RLE compress the data to the existing buffer res = dmEncodeGenericRLE(buf, &mem, &cfg); out: dmGrowBufFree(&mem); return res; } static int fmtProbeGunPaint(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { if (len > 0x400 && dmCompareAddr16(buf, 0, fmt->addr) && memcmp(buf + 0x3ea, "GUNPAINT (JZ) ", 14) == 0) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } static int fmtProbeAmicaPaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { size_t i, n; if (len < 256 || !dmCompareAddr16(buf, 0, fmt->addr)) return DM_PROBE_SCORE_FALSE; // Interpaint Hi-Res gives a false positive // as do some GunPaint images .. if (len == 9002 || fmtProbeGunPaint(buf, len, fmt) > DM_PROBE_SCORE_GOOD) return DM_PROBE_SCORE_FALSE; for (n = 0, i = 2; i < len; i++) if (buf[i] == 0xC2) n++; if (n > 50) return DM_PROBE_SCORE_GOOD; if (n > 25) return DM_PROBE_SCORE_AVG; if (n > 10) return DM_PROBE_SCORE_MAYBE; return DM_PROBE_SCORE_FALSE; } static int fmtDecodeAmicaPaintPacked(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem, tmp; DMCompParams cfg; // Amica Paint apparently is broken and stores one byte less than it should // so we need to do some crappy buffer expansion here .. if (dmGrowBufCopy(&tmp, buf, 1) == NULL) return DMERR_MALLOC; tmp.len = tmp.size; // Now do an RLE decode on the enlarged buffer cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMarkerB = 0xC2; if ((res = dmDecodeGenericRLEAlloc(&mem, &tmp, &cfg)) != DMERR_OK) goto out; // And finally decode to bitmap struct res = dmC64DecodeGenericBMP(img, &mem, fmt); out: dmGrowBufFree(&tmp); dmGrowBufFree(&mem); return res; } static int fmtEncodeAmicaPaintPacked(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem; DMCompParams cfg; // Encode the data to temp buffer if ((res = dmC64EncodeGenericBMP(TRUE, &mem, img, fmt)) != DMERR_OK) goto out; // And now RLE compress the data to the existing buffer cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMarkerB = 0xC2; cfg.rleMinCountB = 3; cfg.rleMaxCountB = 255; res = dmEncodeGenericRLE(buf, &mem, &cfg); out: dmGrowBufFree(&mem); return res; } static int fmtProbeFLIDesigner(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { if (len == fmt->size && (dmCompareAddr16(buf, 0, 0x3c00) || dmCompareAddr16(buf, 0, 0x3ff0))) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } static BOOL fmtTruePaintGetLaceType(DMC64Image *img, const DMC64EncDecOp *op, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { (void) op; (void) buf; (void) fmt; img->laceType = D64_ILACE_RES; return TRUE; } static Uint8 fmtGetPixelTruePaint( const DMC64Image *img, const int bmoffs, const int scroffs, const int vshift, const int vbitmap, const int raster) { (void) raster; return dmC64GetGenericMCPixel(img, bmoffs, scroffs, vshift, 0, vbitmap, 0, img->bgcolor); } static int fmtProbeTruePaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { // The beginning/un-changing part of the BASIC bootstrap and // relocation of decompression code static const Uint8 magicID[] = { 0x0b, 0x08, 0x09, 0x00, 0x9e, 0x32, 0x30, 0x35, 0x39, 0x00, 0xa2, 0x00, 0x78, 0xbd, 0x1c, 0x08, 0x9d, 0xf5, 0x00, 0xe8, 0xd0, 0xf7, 0xe6, 0x01, 0x4c, 0x01, 0x01, 0xa5, 0xfe, 0xd0, 0x02, 0xc6, 0xff, 0xc6, 0xfe }; if (len >= 512 && dmCompareAddr16(buf, 0, fmt->addr) && memcmp(buf + 2, magicID, sizeof(magicID)) == 0) return DM_PROBE_SCORE_MAX; return DM_PROBE_SCORE_FALSE; } // // Based on disassembly of the depacker routine. Encoding seems to be // some kind of "improved RLE" variant with different modes and a // simplistic "codebook". // static int fmtTruePaintGetByte(DMGrowBuf *src, Uint8 *data, const int mode) { if (!dmGrowBufGetU8(src, data)) { return dmError(DMERR_INVALID_DATA, "TruePaintRLE: Out of input data (N=%d)\n", mode); } else return DMERR_OK; } static int fmtDecodeTruePaintPacked(DMC64Image *img, const DMGrowBuf *psrc, const DMC64ImageFormat *fmt) { int res = DMERR_OK; const Uint8 *codeBook1, *codeBook2; DMGrowBuf dst, src; DMCompParams cfg; Uint8 data; // 1b7e-67e8 decoded by original depacker // 1c00-67e8 is the actual area used tho cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BACKWARDS_OUTPUT | DM_RLE_BACKWARDS_INPUT | DM_OUT_CROP_END; cfg.rleMarkerB = 0xfe; cfg.cropOutLen = 0x67e8 - 0x1c00; // Codebooks: #1 is trampoline table markers, #2 is RLE data table codeBook1 = psrc->data + 0x81 - 2; codeBook2 = psrc->data + 0x85 - 2; // Allocate output buffer if ((res = dmGrowBufAlloc(&dst, 64*1024, 4*1024)) != DMERR_OK) goto out; // As we need to modify the offs, etc. but not the data, // we will just make a shallow copy of the DMGrowBuf struct dmGrowBufConstCopy(&src, psrc); dmSetupRLEBuffers(&dst, &src, &cfg); while ((res = fmtTruePaintGetByte(&src, &data, -1)) == DMERR_OK) { unsigned int count = 1; BOOL found = FALSE; for (int n = 0; n < 8; n++) if (codeBook1[n] == data && !found) { found = TRUE; switch (n) { case 4: // Y = 4, JTO = $0B if ((res = fmtTruePaintGetByte(&src, &data, n)) != DMERR_OK) goto out; count = data; if (data == 0) goto finish; // fallthrough case 1: // Y = 1, JTO = $17 count += 2; // fallthrough case 0: // Y = 0, JTO = $19 if ((res = fmtTruePaintGetByte(&src, &data, n)) != DMERR_OK) goto out; break; case 2: // Y = 2, JTO = $07 if ((res = fmtTruePaintGetByte(&src, &data, n)) != DMERR_OK) goto out; count = data; // fallthrough case 3: // Y = 3, JTO = $0B count += 2; data = 0; break; default: // Y = [5..8], JTO = $00 count++; data = codeBook2[n]; break; } } if ((res = dmGenericRLEOutputRun(&dst, &cfg, data, count)) != DMERR_OK) goto out; } finish: dmFinishRLEBuffers(&dst, &src, &cfg); res = dmC64DecodeGenericBMP(img, &dst, fmt); out: dmGrowBufFree(&dst); return res; } #define XX2_MIN_SIZE 4000 #define XX2_WIDTH_CH 40 #define XX2_HEIGHT_CH 10 #define XX2_SIZE (XX2_WIDTH_CH * XX2_HEIGHT_CH) #define XX2_BSIZE (XX2_SIZE * 8) static int fmtProbeFormatXX2(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { if (len >= XX2_MIN_SIZE && len <= XX2_MIN_SIZE + 8 && dmCompareAddr16(buf, 0, fmt->addr)) return DM_PROBE_SCORE_MAYBE; return DM_PROBE_SCORE_FALSE; } static int fmtDecodeFormatXX2(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf tmp; // If there is only data for less than XX2_MIN_SIZE bytes, // allocate a buffer of that size and copy data there. // Otherwise allocate len bytes. if (dmGrowBufCopy(&tmp, buf, buf->len < XX2_MIN_SIZE ? XX2_MIN_SIZE - buf->len : 0) == NULL) return DMERR_MALLOC; tmp.len = tmp.size; res = dmC64DecodeGenericBMP(img, &tmp, fmt); dmGrowBufFree(&tmp); return res; } #define FUNPAINT2_HEADER_SIZE (0x10) static const char *fmtFunPaint2MagicID = "FUNPAINT (MT) "; static int fmtProbeFunPaint2(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { if (len > 30 && dmCompareAddr16(buf, 0, fmt->addr) && memcmp(buf + 2, fmtFunPaint2MagicID, strlen(fmtFunPaint2MagicID)) == 0) return DM_PROBE_SCORE_MAX; else return DM_PROBE_SCORE_FALSE; } static int fmtDecodeFunPaint2(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf tmp; // Check if the data is compressed if (buf->data[14]) { DMGrowBuf mem; DMCompParams cfg; cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMarkerB = buf->data[15]; dmGrowBufCopyOffs(&tmp, buf, FUNPAINT2_HEADER_SIZE, 1); tmp.len = tmp.size; if ((res = dmDecodeGenericRLEAlloc( &mem, &tmp, &cfg)) == DMERR_OK) res = dmC64DecodeGenericBMP(img, &mem, fmt); dmGrowBufFree(&mem); dmGrowBufFree(&tmp); } else { res = dmC64DecodeGenericBMP(img, dmGrowBufConstCopyOffs(&tmp, buf, FUNPAINT2_HEADER_SIZE), fmt); } return res; } static int fmtEncodeFunPaint2Unpacked(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { // Add the header bits if (!dmGrowBufPut(buf, (Uint8 *) fmtFunPaint2MagicID, strlen(fmtFunPaint2MagicID)) || !dmGrowBufPutU8(buf, 0)) return DMERR_MALLOC; return dmC64EncodeGenericBMP(FALSE, buf, img, fmt); } static int fmtEncodeFunPaint2Packed(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt) { int res; DMGrowBuf mem; DMCompParams cfg; // Encode the data to temp buffer if ((res = dmC64EncodeGenericBMP(TRUE, &mem, img, fmt)) != DMERR_OK) goto out; // Analyze and setup RLE cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMinCountB = 3; cfg.rleMaxCountB = 255; dmGenericRLEAnalyze(&mem, &cfg); // Add the header bits if (!dmGrowBufPut(buf, (Uint8 *) fmtFunPaint2MagicID, strlen(fmtFunPaint2MagicID)) || !dmGrowBufPutU8(buf, cfg.rleMarkerB)) { res = DMERR_MALLOC; goto out; } // And now RLE compress the data to the existing buffer res = dmEncodeGenericRLE(buf, &mem, &cfg); out: dmGrowBufFree(&mem); return res; } static Uint8 fmtGetPixelFunPaint2( const DMC64Image *img, const int bmoffs, const int scroffs, const int vshift, const int vbitmap, const int raster) { const int vbank = (raster & 7) + (vbitmap * 8); int vr, vb; if (raster < 100) { vb = 0; vr = raster; } else { vb = 0; vr = raster - 100; } return dmC64GetGenericMCPixel( img, bmoffs, scroffs, vshift, vbank, vbitmap, 0, img->extraData[vb].data[vr] & 15); } static Uint8 fmtGetPixelGunPaint( const DMC64Image *img, const int bmoffs, const int scroffs, const int vshift, const int vbitmap, const int raster) { const int vbank = (raster & 7);// + (vbitmap * 8); int vr, vb; if (raster < 177) { vb = 0; vr = raster; } else { vb = 0; vr = raster - 177; } return dmC64GetGenericMCPixel( img, bmoffs, scroffs, vshift, vbank, vbitmap, 0, img->extraData[vb].data[vr] & 15); } static Uint8 fmtGetPixelBFLI( const DMC64Image *img, const int bmoffs, const int scroffs, const int vshift, const int bitmap, const int raster) { const int vbb = bmoffs > 0x1fff ? 1 : 0; const int vbank = (raster & 7) + (vbb * 8); const int vbmoffs = bmoffs & 0x1fff; const int vscroffs = scroffs & 0x3ff; //fprintf(stderr, "bmoffs=%d, scroffs=%d, vshift=%d, vbitmap=%d, raster=%d\n", vbmoffs, vscroffs, vshift, vbb, raster); (void) bitmap; return dmC64GetGenericMCPixel( img, vbmoffs, vscroffs, vshift, vbank, vbb, 0, img->bgcolor); } static Uint8 fmtGetPixelBlackMailFLI( const DMC64Image *img, const int bmoffs, const int scroffs, const int shift, const int bitmap, const int raster) { const int vbank = raster & 7; return dmC64GetGenericMCPixel( img, bmoffs, scroffs, shift, vbank, bitmap, 0, img->extraData[0].data[raster] & 15); } static Uint8 fmtGetPixelFLIDesigner( const DMC64Image *img, const int bmoffs, const int scroffs, const int shift, const int bitmap, const int raster) { return dmC64GetGenericMCPixel(img, bmoffs, scroffs, shift, raster & 7, bitmap, 0, img->bgcolor); } static Uint8 fmtGetPixelCrestHIFLIorCDHM( const DMC64Image *img, const int bmoffs, const int scroffs, const int shift, const int bitmap, const int raster) { const int vbank = raster & 7; if ((img->bitmap[bitmap].data[bmoffs] >> shift) & 1) return img->screen[vbank].data[scroffs] >> 4; else return img->screen[vbank].data[scroffs] & 15; } static BOOL fmtECIGetLaceType(DMC64Image *img, const DMC64EncDecOp *op, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { (void) op; (void) buf; (void) fmt; img->laceType = D64_ILACE_COLOR; return TRUE; } static Uint8 fmtGetPixelECI( const DMC64Image *img, const int bmoffs, const int scroffs, const int shift, const int bitmap, const int raster) { const int vbank = raster & 7; Uint8 c1 = dmC64GetGenericSCPixel(img, bmoffs, scroffs, shift, vbank , 0, 0), c2 = dmC64GetGenericSCPixel(img, bmoffs, scroffs, shift, vbank + 8, 1, 0); (void) bitmap; return (c1 * C64_NCOLORS) + c2; } static int fmtConvertECIBMP2Image(DMImage *dst, const DMC64Image *src, const DMC64ImageFormat *fmt) { if (!dmSetMixedColorC64Palette(dst)) return DMERR_MALLOC; return dmC64ConvertGenericBMP2Image(dst, src, fmt); } static int fmtProbeECIPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt) { size_t i, n; // XXX TODO: Perhaps count statistics about used byte values // and compare to value in buf[2] which is the RLE marker if (len < 128 || !dmCompareAddr16(buf, 0, fmt->addr) || // Try to avoid misprobe of Crest Hires FLI Designer and Cosmos Design format len == 16386 || len == 16385) return DM_PROBE_SCORE_FALSE; for (n = 0, i = 3; i < len; i++) if (buf[i] == buf[2]) n++; if (n > 50) return DM_PROBE_SCORE_GOOD; if (n > 25) return DM_PROBE_SCORE_AVG; if (n > 10) return DM_PROBE_SCORE_MAYBE; return DM_PROBE_SCORE_FALSE; } static int fmtDecodeECIPacked(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) { int res; DMGrowBuf tmp; DMGrowBuf mem; DMCompParams cfg; cfg.func = fmt->name; cfg.type = DM_COMP_RLE_MARKER; cfg.flags = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1; cfg.rleMarkerB = buf->data[0]; if ((res = dmDecodeGenericRLEAlloc( &mem, dmGrowBufConstCopyOffs(&tmp, buf, 1), &cfg)) == DMERR_OK) res = dmC64DecodeGenericBMP(img, &mem, fmt); dmGrowBufFree(&mem); return res; } // // Helper macros for defining screen ram layouts // common for FLI type foramts // #define DEF_SCREEN_RAM(start, oindex, bindex, osize) { DO_COPY, DS_SCREEN_RAM, (start) + ((osize) * (oindex)), (bindex), 0, NULL, NULL } #define DEF_SCREEN_RAMS_8(start, sindex, osize) \ DEF_SCREEN_RAM((start), 0, (sindex + 0), (osize)), \ DEF_SCREEN_RAM((start), 1, (sindex + 1), (osize)), \ DEF_SCREEN_RAM((start), 2, (sindex + 2), (osize)), \ DEF_SCREEN_RAM((start), 3, (sindex + 3), (osize)), \ DEF_SCREEN_RAM((start), 4, (sindex + 4), (osize)), \ DEF_SCREEN_RAM((start), 5, (sindex + 5), (osize)), \ DEF_SCREEN_RAM((start), 6, (sindex + 6), (osize)), \ DEF_SCREEN_RAM((start), 7, (sindex + 7), (osize)) // // Many formats actually share memory layout, and there are packed and // unpacked versions of several formats. We'll reuse these here through // this common formats ops array, referred from dmC64ImageFormats[] // const DMC64EncDecOpList dmC64CommonFormatOps[] = { { // #0: Koala Paint type memory layout { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x1f40, 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x2328, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x2710, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #1: Amica Paint, Run Paint, etc. layout { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x1f40, 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x2328, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x2710, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #2: Art Studio etc. Hires { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x1f40, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #3: FunPaint II DEF_SCREEN_RAMS_8(0x0000, 0, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x2000, 0, 0, NULL, NULL }, { DO_COPY , DS_EXTRA_DATA , 0x3f40, 0, 100, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x4000, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x43e8, 8, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x63e8, 1, 0, NULL, NULL }, { DO_COPY , DS_EXTRA_DATA , 0x8328, 1, 100, NULL, NULL }, { DO_DEC_FUNC , 0 , 0x2742, 0, 1, fmtTruePaintGetLaceType, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #4: DrazPaint 1.x & 2 { DO_COPY , DS_COLOR_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0800, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x2740, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #5: DrazLace 1.0 { DO_COPY , DS_COLOR_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0800, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x2740, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x2800, 1, 0, NULL, NULL }, { DO_DEC_FUNC , 0 , 0x2742, 0, 1, fmtDrazLaceGetLaceType, NULL }, { DO_ENC_FUNC , 0 , 0x2742, 0, 1, NULL, fmtDrazLaceSetLaceType }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #6: TruePaint { DO_COPY , DS_SCREEN_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x03e8, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x2400, 1, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x4400, 1, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x4800, 0, 0, NULL, NULL }, { DO_DEC_FUNC , 0 , 0x0000, 0, 0, fmtTruePaintGetLaceType, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, { // #7: ECI Graphic Editor Hires FLI { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x2000, 0, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x4000, 1, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x6000, 8, 0x400), { DO_DEC_FUNC , 0 , 0 , 0, 0, fmtECIGetLaceType, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, }; // // Array with data for supported formats // const DMC64ImageFormat dmC64ImageFormats[] = { { D64_FMT_MC, "d2p", "DrazPaint 1.4/2.0 (packed)", 0x5800, 0, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeDrazPaint20Packed, fmtDecodeDrazPaintPacked, fmtEncodeDrazPaintPacked, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[4] }, { D64_FMT_MC, "drp", "DrazPaint (unpacked)", 0x5800, 10051, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[4] }, { D64_FMT_MC | D64_FMT_ILACE, "dlp", "DrazLace 1.0 (packed)", 0x5800, 0, DM_FMT_RDWR, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, fmtProbeDrazLace10Packed, fmtDecodeDrazPaintPacked, fmtEncodeDrazPaintPacked, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[5] }, { D64_FMT_MC | D64_FMT_ILACE, "drl", "DrazLace 1.0 (unpacked)", 0x5800, 18242, DM_FMT_RDWR, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[5] }, { D64_FMT_MC, "bdp5", "Boogie Down Paint 5 (packed)", 0x5000, 0, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeBDP5Packed, fmtDecodeBDP5Packed, fmtEncodeBDP5Packed, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[0] // Memory format is same as Koala }, { D64_FMT_MC, "vid", "Vidcom 64 (unpacked)", 0x5800, 10050, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_COLOR_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x07e8, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0800, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "p64", "Picasso 64 (unpacked)", 0x1800, 10050, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_COLOR_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x07fe, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0800, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC | D64_FMT_ILACE, "mci", "Truepaint (unpacked)", 0x9c00, 19434, DM_FMT_RD, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, fmtGetPixelTruePaint, { }, &dmC64CommonFormatOps[6] }, { D64_FMT_MC | D64_FMT_ILACE, "mcip", "Truepaint (packed)", 0x0801, 0, DM_FMT_RD, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, fmtProbeTruePaintPacked, fmtDecodeTruePaintPacked, NULL, NULL, NULL, fmtGetPixelTruePaint, { }, &dmC64CommonFormatOps[6] }, { D64_FMT_MC, "kla", "Koala Paint (unpacked)", 0x6000, 10003, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[0] }, { D64_FMT_MC, "klp", "Koala Paint (packed)", 0x6000, 0, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeKoalaPaintPacked, fmtDecodeKoalaPaintPacked, fmtEncodeKoalaPaintPacked, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[0] }, { D64_FMT_MC, "aas", "Advanced Art Studio (unpacked)", 0x2000, 10018, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x1f40, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x2329, 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x2338, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "ims", "Image System (unpacked)", 0x3c00, 10218, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_COLOR_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x23ff, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x2400, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "mil", "MIL (unpacked)", 0x18dc, 10022, DM_FMT_RDWR | DM_FMT_BROKEN, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_SCREEN_RAM , 20 + 0 , 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 20 + 1000, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 20 + 2000, 0, 0, NULL, NULL }, // XXX TODO: Unknown where the background color is set, so default to 0x01 //{ DO_SET_MEM , DS_BGCOL , 0x23ff, 0, 0, NULL, NULL }, { DO_SET_OP , DS_BGCOL , 0x01 , 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "cdu", "CDU-Paint (unpacked)", 0x7eef, 10277, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x0000 + 0x111, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x1f40 + 0x111, 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x2328 + 0x111, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x2710 + 0x111, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "rbp", "Rainbow Painter (unpacked)", 0x5c00, 10242, DM_FMT_RDWR | DM_FMT_BROKEN, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_SCREEN_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x2400, 0, 0, NULL, NULL }, // XXX TODO: Not sure if the background color is hardcoded .. { DO_SET_OP , DS_BGCOL , 0x00 , 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "pmg", "PMG crippled multicolor (unpacked)", 0x3f8e, 9332, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x4000 + 0x72 - 0x4000, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x6000 + 0x72 - 0x4000, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_COLOR_RAM , 0x5f43 + 0x72 - 0x4000, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_BGCOL , 0x5f44 + 0x72 - 0x4000, 0, 0, NULL, NULL }, { DO_SET_MEM , DS_D020 , 0x5f40 + 0x72 - 0x4000, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "ami", "Amica Paint (packed)", 0x4000, 0, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeAmicaPaintPacked, fmtDecodeAmicaPaintPacked, fmtEncodeAmicaPaintPacked, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[1] }, { D64_FMT_MC, "rpm", "Run Paint (unpacked)", 0x6000, 10006, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[1] }, { D64_FMT_MC, "ipc", "Interpaint MC (unpacked)", 0x4000, 10003, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[1] }, { D64_FMT_HIRES, "art", "Art Studio (unpacked)", 0x2000, 9009, DM_FMT_RD, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[2] }, { D64_FMT_HIRES, "iph", "Interpaint (unpacked)", 0x4000, 9002, DM_FMT_RD, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { }, &dmC64CommonFormatOps[2] }, { D64_FMT_HIRES, "dd", "Doodle (unpacked)", 0x1c00, 9218, DM_FMT_RDWR, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_SCREEN_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_BITMAP_RAM , 0x0400, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_HIRES, "mon", "Monomagic (unpacked)", 0x2000, 8194, DM_FMT_RDWR, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_SET_OP , DS_SCREEN_RAM , 0xCF , 0, 0, NULL, NULL }, // Default colors used by MM are --^^ { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_HIRES, "hir", "Plain hires (unpacked)", 0x2000, 8002, DM_FMT_RDWR, C64_SCR_WIDTH , C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_SET_OP , DS_SCREEN_RAM , 0xF0 , 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC | D64_FMT_FLI, "bfli", "Big FLI (unpacked)", 0x3bff, 33795, DM_FMT_RD | DM_FMT_BROKEN, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT * 2, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, fmtGetPixelBFLI, { { DO_COPY , DS_COLOR_RAM , 0x0001, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x0401, 0, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x2401, 0, 0x1fff, NULL, NULL }, DEF_SCREEN_RAMS_8(0x4401, 8, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x6401, 1, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC | D64_FMT_FLI, "bml", "Blackmail FLI (unpacked)", 0x3b00, 17474, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, fmtGetPixelBlackMailFLI, { { DO_COPY , DS_EXTRA_DATA , 0x0000, 0, 200, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x0100, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x0500, 0, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x2500, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC | D64_FMT_FLI, "fli", "FLI Designer (unpacked)", 0, 17409, DM_FMT_RD, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeFLIDesigner, NULL, NULL, NULL, NULL, fmtGetPixelFLIDesigner, { { DO_COPY , DS_COLOR_RAM , 0x0000, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x0400, 0, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x2400, 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_HIRES | D64_FMT_FLI, "eci", "ECI Graphic Editor 1.0 (unpacked)", 0x4000, 32770, DM_FMT_RD, C64_SCR_WIDTH, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, NULL, NULL, NULL, fmtConvertECIBMP2Image, NULL, fmtGetPixelECI, { }, &dmC64CommonFormatOps[7] }, { D64_FMT_HIRES | D64_FMT_FLI, "ecp", "ECI Graphic Editor 1.0 (packed)", 0x4000, 0, DM_FMT_RD, C64_SCR_WIDTH, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH, C64_SCR_CH_HEIGHT, fmtProbeECIPacked, fmtDecodeECIPacked, NULL, fmtConvertECIBMP2Image, NULL, fmtGetPixelECI, { }, &dmC64CommonFormatOps[7] }, { D64_FMT_MC, "xx1", "Unknown $2000 format (unpacked)", 0x2000, 10242, DM_FMT_RDWR, C64_SCR_WIDTH / 2, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, NULL, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , 0x2000, 0, 0, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x2400, 0, 0, NULL, NULL }, { DO_SET_OP , DS_BGCOL , 0x00 , 0, 0, NULL, NULL }, { DO_SET_OP , DS_EXTRA_DATA , 10240 , 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC, "xx2", "Unknown $2000 format (unpacked)", 0x2000, 0, DM_FMT_RDWR, XX2_WIDTH_CH * 4, XX2_HEIGHT_CH * 8, XX2_WIDTH_CH , XX2_HEIGHT_CH, fmtProbeFormatXX2, fmtDecodeFormatXX2, NULL, NULL, NULL, NULL, { { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, XX2_BSIZE, NULL, NULL }, { DO_COPY , DS_SCREEN_RAM , XX2_BSIZE, 0, XX2_SIZE, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , XX2_BSIZE + XX2_SIZE, 0, XX2_SIZE, NULL, NULL }, { DO_SET_OP , DS_BGCOL , 11 , 0, 0, NULL, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_MC | D64_FMT_FLI | D64_FMT_ILACE, "fp2", "FunPaint II (unpacked)", 0x3ff0, 33694, DM_FMT_RD, C64_SCR_WIDTH, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeFunPaint2, fmtDecodeFunPaint2, fmtEncodeFunPaint2Unpacked, NULL, NULL, fmtGetPixelFunPaint2, { }, &dmC64CommonFormatOps[3] }, { D64_FMT_MC | D64_FMT_FLI | D64_FMT_ILACE, "fp2p", "FunPaint II (packed)", 0x3ff0, 0, DM_FMT_RD, C64_SCR_WIDTH, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, NULL, fmtDecodeFunPaint2, fmtEncodeFunPaint2Packed, NULL, NULL, fmtGetPixelFunPaint2, { }, &dmC64CommonFormatOps[3] }, { D64_FMT_MC | D64_FMT_FLI | D64_FMT_ILACE, "gun", "GunPaint (unpacked)", 0x4000, 0, DM_FMT_RD, C64_SCR_WIDTH, C64_SCR_HEIGHT, C64_SCR_CH_WIDTH , C64_SCR_CH_HEIGHT, fmtProbeGunPaint, NULL, NULL, NULL, NULL, fmtGetPixelGunPaint, { DEF_SCREEN_RAMS_8(0x0000, 0, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x2000, 0, 0, NULL, NULL }, { DO_COPY , DS_EXTRA_DATA , 0x3f4f, 0, 177, NULL, NULL }, { DO_COPY , DS_COLOR_RAM , 0x4000, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x4400, 8, 0x400), { DO_COPY , DS_BITMAP_RAM , 0x6400, 1, 0, NULL, NULL }, { DO_COPY , DS_EXTRA_DATA , 0x47e8, 1, 20, NULL, NULL }, { DO_DEC_FUNC , 0 , 0x2742, 0, 1, fmtTruePaintGetLaceType, NULL }, { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, { D64_FMT_HIRES | D64_FMT_FLI, "chi", "Crest Hires FLI Designer (unpacked)", 0x4000, 16386, DM_FMT_RD, C64_SCR_WIDTH, 14 * 8, C64_SCR_CH_WIDTH , 14, NULL, NULL, NULL, NULL, NULL, fmtGetPixelCrestHIFLIorCDHM, { { DO_COPY , DS_BITMAP_RAM , 0x0000, 0, 0, NULL, NULL }, DEF_SCREEN_RAMS_8(0x2000, 0, 0x400), { DO_LAST , 0 , 0 , 0, 0, NULL, NULL }, }, NULL }, }; const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);