changeset 2189:83391646ff16

Add read support for packed version of Crest Super Hires FLI format.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 13 Jun 2019 07:49:45 +0300
parents 9b7d5e219d4b
children 0447f4c6c32b
files tools/lib64fmts.c
diffstat 1 files changed, 179 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/tools/lib64fmts.c	Thu Jun 13 00:01:54 2019 +0300
+++ b/tools/lib64fmts.c	Thu Jun 13 07:49:45 2019 +0300
@@ -1236,6 +1236,12 @@
 };
 
 
+static const Uint8 fmtCrestSHFLI_MagicID_Packed[] =
+{
+    0x83, 0x92, 0x85, 0x93, 0x94,
+};
+
+
 static int fmtProbeCrestSHFLI(const DMGrowBuf *buf, const DMC64ImageFormat *fmt)
 {
     // Unpacked variant
@@ -1252,10 +1258,158 @@
         return score;
     }
 
+    // Packed variant
+    if (dmCompareAddr16(buf, 0, fmt->addr) &&
+        buf->len > sizeof(fmtCrestSHFLI_MagicID_Packed) &&
+        DM_MEMCMP_SIZE(buf->data + buf->len - sizeof(fmtCrestSHFLI_MagicID_Packed), fmtCrestSHFLI_MagicID_Packed) == 0)
+        return DM_PROBE_SCORE_MAX;
+
     return DM_PROBE_SCORE_FALSE;
 }
 
 
+static int fmtDecodeCrestSHFLIPacked(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt)
+{
+    int res;
+    DMGrowBuf tmp, mem;
+    DMCompParams cfg;
+
+    // Compression is typical RLE, with first byte being the RLE marker byte etc.
+    // However, as a difference to the uncompressed files, only the data of the
+    // 96 pixels wide area (4 sprite widths) x 168 tall is saved.
+    cfg.func         = fmt->name;
+    cfg.type         = DM_COMP_RLE_MARKER;
+    cfg.flags        = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1 | DM_RLE_ZERO_COUNT_MAX;
+    cfg.rleMarkerB   = buf->data[0];
+
+    if ((res = dmDecodeGenericRLEAlloc(
+        &mem, dmGrowBufConstCopyOffs(&tmp, buf, 1), &cfg)) == DMERR_OK)
+    {
+        const size_t fmtUncompSize = 0x1ff0;
+        const size_t dstSize = 16 * 1024;
+        const int imgXOffs = 14;
+        const int imgWidth = 4 * D64_SPR_WIDTH_UT;
+        Uint8 *dstBuf, *sptr, *dptr;
+
+        // Check uncompressed size?
+        if (mem.len != fmtUncompSize)
+        {
+            res = dmError(DMERR_INVALID_DATA,
+                "%s: Unexpected uncompressed data size %d bytes (should be %d).\n",
+                cfg.func, mem.len, fmtUncompSize);
+            goto out;
+        }
+
+        // Allocate output buffer
+        if ((dstBuf = dmMalloc0(dstSize)) == NULL)
+        {
+            res = dmError(DMERR_MALLOC,
+                "%s: Could not allocate temporary memory buffer of %d bytes.\n",
+                cfg.func, dstSize);
+            goto out;
+        }
+
+        // Now that we have the uncompressed data (0x1ff0 bytes), we need to
+        // re-arrange it. The data is as follows ..
+        //
+        // 0x0000 - sprite data for 64 sprites
+        // 0x1000 - bitmap (12 * 21 bytes)
+        // 0x1800 - screen RAMs (12 * 21 bytes) x 8 banks
+        // 0x1fe8 - sprite color #1
+        // 0x1fe9 - sprite color #2
+        //
+
+        // Copy sprite colors
+        sptr = mem.data + 0x1fe8;
+        dptr = dstBuf   + 0x03e8;
+        dptr[0] = sptr[0];
+        dptr[1] = sptr[1];
+
+        // First, clear and set some defaults that are not saved in the file
+        for (int nbank = 0; nbank < DM_CREST_SHFLI_BANKS; nbank++)
+        {
+            dptr = dstBuf + nbank * 0x0400;
+
+            // Set preset screen RAM for other area
+            memset(dptr, 0xff, fmt->format->chWidth * fmt->format->chHeight);
+
+            // Copy sprite data points
+            memcpy(dptr + 0x03f8, &fmtCrestSHFLI_Sprite_pointers[nbank], DM_CREST_SHFLI_PTRS);
+        }
+
+        // Now we copy and transform the bitmap and screen RAM data.
+        for (int yc = 0; yc < fmt->format->chHeight * 8; yc++)
+        {
+            const int syy = yc / 8;
+            const int syd = yc & 7;
+
+            // In the image the first visible scanline is unused, but in
+            // the compressed version data starts right away, so we offset
+            // the destination Y coordinate by one.
+            const int dyc = yc + 1;
+            const int dyy = dyc / 8;
+            const int dyd = dyc & 7;
+
+            // Format of the bitmap data is one horizontal pixel row (12 bytes)
+            // times 21*8 rows, e.g. the data is "linear" rows of bytes and not
+            // arranged in usual c64 bitmap "char" order. Thus we reorder it.
+            sptr = mem.data + 0x1000 + imgWidth * (syd + 8 * syy);
+            dptr = dstBuf   + 0x2000 + imgXOffs * 8 + (fmt->format->chWidth * dyy * 8) + dyd;
+
+            for (int xc = 0; xc < imgWidth; xc++)
+            {
+                dptr[xc * 8] = sptr[xc];
+                sptr[xc] = 0xaa;
+            }
+
+            // A bit similar arrangement is used for the screen RAM data.
+            // Each row of 12 bytes of data is for a bank. Next row is for
+            // next bank, etc.
+            sptr = mem.data + 0x1800 + imgWidth * syd + imgWidth * 8 * syy;
+            dptr = dstBuf + imgXOffs + 0x0400 * dyd + fmt->format->chWidth * dyy;
+
+            for (int xc = 0; xc < imgWidth; xc++)
+            {
+                dptr[xc] = sptr[xc];
+                sptr[xc] = 0xaa;
+            }
+        }
+
+        // The sprite data is also transformed similarly, data is
+        // in same scanline format as the bitmap. Thus we need to
+        // place it where it belongs based on the sprite pointers.
+        for (int yc = 0; yc < fmt->format->chHeight * 8; yc++)
+        {
+            const int yd = yc % 21;
+            Uint8 *sp1, *sp2, *dp, *sprPtrs = fmtCrestSHFLI_Sprite_pointers[yc % 8];
+
+            dptr = dstBuf + 3 * yd;
+            sp1 = mem.data + imgWidth * yc;
+            sp2 = sp1 + 0x800;
+
+            for (int xc = 0; xc < 4; xc++)
+            {
+                dp = dptr + D64_SPR_SIZE * sprPtrs[xc];
+                for (int xd = 0; xd < D64_SPR_WIDTH_UT; xd++)
+                    dp[xd] = *sp1++;
+
+                dp = dptr + D64_SPR_SIZE * sprPtrs[xc + 4];
+                for (int xd = 0; xd < D64_SPR_WIDTH_UT; xd++)
+                    dp[xd] = *sp2++;
+            }
+        }
+
+        res = dmC64DecodeGenericBMP(img, dmGrowBufConstCreateFrom(&tmp, dstBuf, dstSize), fmt);
+        dmFree(dstBuf);
+    }
+
+out:
+    dmGrowBufFree(&mem);
+
+    return res;
+}
+
+
 static int fmtGetSpritePixelCrestSHFLI(Uint8 *col,
     const DMC64Image *img, const int sindex, const int cindex,
     const int spr_xd, const int spr_yd, const int mask)
@@ -1681,6 +1835,23 @@
             { DO_LAST       , 0              , 0     , 0,  0,   0, NULL, NULL },
         }
     },
+
+    { // #11: Crest Super Hires FLI Editor 1.0 (SHF)
+        D64_FMT_HIRES | D64_FMT_FLI,
+        D64_SCR_WIDTH, D64_SCR_HEIGHT,
+        D64_SCR_CH_WIDTH, 21,
+        1, 1,
+        NULL, NULL,
+        fmtGetPixelCrestSHFLI,
+        {
+            DEF_REPEAT_BLOCK_8(DS_SCREEN_RAM,  0x0000, 0 , 0x0400, 0),
+            DEF_REPEAT_BLOCK_8(DS_EXTRA_DATA,  0x03f8, 0 , 0x0400, 8), // Sprite pointers for each bank
+            { DO_COPY       , DS_EXTRA_DATA  , 0x03e8, 15, 2     ,   0, NULL, NULL },  // 2 sprite colors
+            { DO_COPY       , DS_EXTRA_DATA  , 0x0000, 14, 0x3e00,   0, NULL, NULL },  // Lazily copy whole data for sprite data
+            { DO_COPY       , DS_BITMAP_RAM  , 0x2000, 0 , 0     ,   0, NULL, NULL },
+            { DO_LAST       , 0              , 0     , 0 , 0     ,   0, NULL, NULL },
+        }
+    },
 };
 
 
@@ -2359,23 +2530,14 @@
         "cshf", "Crest Super Hires FLI Editor v1.0 (unpacked)", 0x4000, 15874, DM_FMT_RD,
         fmtProbeCrestSHFLI,
         NULL, NULL,
-        {
-            D64_FMT_HIRES | D64_FMT_FLI,
-            D64_SCR_WIDTH, D64_SCR_HEIGHT,
-            D64_SCR_CH_WIDTH, 21,
-            1, 1,
-            NULL, NULL,
-            fmtGetPixelCrestSHFLI,
-            {
-                DEF_REPEAT_BLOCK_8(DS_SCREEN_RAM,  0x0000, 0, 0x400, 0),
-                DEF_REPEAT_BLOCK_8(DS_EXTRA_DATA,  0x03f8, 0, 0x400, 8), // Sprite pointers for each bank
-                { DO_COPY       , DS_EXTRA_DATA  , 0x03e8, 15, 2     ,   0, NULL, NULL },  // 2 sprite colors
-                { DO_COPY       , DS_EXTRA_DATA  , 0x0000, 14, 0x3e00,   0, NULL, NULL },  // Lazily copy whole data for sprite data
-                { DO_COPY       , DS_BITMAP_RAM  , 0x2000, 0,  0,   0, NULL, NULL },
-                { DO_LAST       , 0              , 0     , 0,  0,   0, NULL, NULL },
-            }
-        },
-        NULL
+        { }, &dmC64CommonFormats[11]
+    },
+
+    {
+        "cshfp", "Crest Super Hires FLI Editor v1.0 (packed)", 0xa000, 0, DM_FMT_RD,
+        fmtProbeCrestSHFLI,
+        fmtDecodeCrestSHFLIPacked, NULL,
+        { }, &dmC64CommonFormats[11]
     },
 
     {