changeset 489:fca3c240ccac

Implement simplistic image input to char/sprite splitter conversion.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 12 Nov 2012 22:04:17 +0200
parents 49f0ce2cc347
children 7e376a853105
files gfxconv.c
diffstat 1 files changed, 170 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/gfxconv.c	Mon Nov 12 22:02:47 2012 +0200
+++ b/gfxconv.c	Mon Nov 12 22:04:17 2012 +0200
@@ -84,11 +84,11 @@
     },
 
     {
-        "C64 character/font data", "chr", TRUE, FALSE,
+        "C64 character/font data", "chr", TRUE, TRUE,
         FFMT_CHAR   , 0
     },
     {
-        "C64 sprite data", "spr", TRUE, FALSE,
+        "C64 sprite data", "spr", TRUE, TRUE,
         FFMT_SPRITE , 0
     },
 };
@@ -138,7 +138,7 @@
     { 15, 'v', "verbose",      "Increase verbosity", OPT_NONE },
     {  3, 'o', "output",       "Output filename", OPT_ARGREQ },
     {  1, 'i', "informat",     "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ },
-    {  2, 'm', "multicolor",   "Input is multicolor", OPT_NONE },
+    {  2, 'm', "multicolor",   "Input is multicolor / output in multicolor", OPT_NONE },
     {  4, 's', "skip",         "Skip bytes in input", OPT_ARGREQ },
     {  5, 'f', "format",       "Output format (see --formats)", OPT_ARGREQ },
     { 17, 'F', "formats",      "Output format (see list below)", OPT_NONE },
@@ -1014,6 +1014,168 @@
 }
 
 
+Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor)
+{
+    Uint8 byte = 0;
+    int xc;
+
+    if (multicolor)
+    {
+        for (xc = 0; xc < 8 / 2; xc++)
+        {
+            Uint8 pixel = sp[xc * 2] & 3;
+            byte |= pixel << (6 - (xc * 2));
+        }
+    }
+    else
+    {
+        for (xc = 0; xc < 8; xc++)
+        {
+            Uint8 pixel = sp[xc] == 0 ? 0 : 1;
+            byte |= pixel << (7 - xc);
+        }
+    }
+
+    return byte;
+}
+
+
+BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image,
+    const int xoffs, const int yoffs, const BOOL multicolor)
+{
+    int yc;
+
+    if (xoffs < 0 || yoffs < 0 ||
+        xoffs + C64_CHR_WIDTH_PX > image->width ||
+        yoffs + C64_CHR_HEIGHT > image->height)
+        return FALSE;
+
+    for (yc = 0; yc < C64_CHR_HEIGHT; yc++)
+    {
+        const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs;
+        buf[yc] = dmConvertByte(sp, multicolor);
+    }
+
+    return TRUE;
+}
+
+
+BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image,
+    const int xoffs, const int yoffs, const BOOL multicolor)
+{
+    int yc, xc;
+
+    if (xoffs < 0 || yoffs < 0 ||
+        xoffs + C64_SPR_WIDTH_PX > image->width ||
+        yoffs + C64_SPR_HEIGHT > image->height)
+        return FALSE;
+
+    for (yc = 0; yc < C64_SPR_HEIGHT; yc++)
+    {
+        for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++)
+        {
+            const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs;
+            buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor);
+        }
+    }
+
+    return TRUE;
+}
+
+
+int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor)
+{
+    int outBlockW, outBlockH, bx, by;
+    FILE *outFile = NULL;
+    Uint8 *buf = NULL;
+    char *outType;
+    size_t bufSize;
+
+    switch (outFormat)
+    {
+        case FFMT_CHAR:
+            bufSize = C64_CHR_SIZE;
+            outBlockW = image->width / C64_CHR_WIDTH_PX;
+            outBlockH = image->height / C64_CHR_HEIGHT;
+            outType = "char";
+            break;
+
+        case FFMT_SPRITE:
+            bufSize = C64_SPR_SIZE;
+            outBlockW = image->width / C64_SPR_WIDTH_PX;
+            outBlockH = image->height / C64_SPR_HEIGHT;
+            outType = "sprite";
+            break;
+
+        default:
+            dmError("Invalid output format %d, internal error.\n", outFormat);
+            goto error;
+    }
+
+    if (outBlockW <= 0 || outBlockH <= 0)
+    {
+        dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n",
+            outBlockW, outBlockH);
+        goto error;
+    }
+
+    if ((outFile = fopen(filename, "wb")) == NULL)
+    {
+        int err = dmGetErrno();
+        dmError("Could not open '%s' for writing, %d: %s.\n",
+            filename, err, dmErrorStr(err));
+        goto error;
+    }
+
+    if ((buf = dmMalloc(bufSize)) == NULL)
+    {
+        dmError("Could not allocate %d bytes for conversion buffer.\n",
+            bufSize);
+        goto error;
+    }
+
+    dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n",
+        outBlockW, outBlockH, outBlockW * outBlockH, outType);
+
+    for (by = 0; by < outBlockH; by++)
+    for (bx = 0; bx < outBlockW; bx++)
+    {
+        switch (outFormat)
+        {
+            case FFMT_CHAR:
+                if (!dmConvertImage2Char(buf, image,
+                    bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT,
+                    multicolor))
+                    goto error;
+                break;
+
+            case FFMT_SPRITE:
+                if (!dmConvertImage2Sprite(buf, image,
+                    bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT,
+                    multicolor))
+                    goto error;
+        }
+
+        if (!dm_fwrite_str(outFile, buf, bufSize))
+        {
+            int err = dmGetErrno();
+            dmError("Error writing data block %d,%d to '%s', %d: %s\n",
+                bx, by, filename, err, dmErrorStr(err));
+            goto error;
+        }
+    }
+
+    fclose(outFile);
+    dmFree(buf);
+    return 0;
+
+error:
+    if (outFile != NULL)
+        fclose(outFile);
+    dmFree(buf);
+    return -1;
+}
+
 int dmDumpSpritesAndChars(FILE *inFile)
 {
     int dataOffs, itemCount, outWidth, outWidthPX, outHeight;
@@ -1407,6 +1569,11 @@
                         res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE);
                         break;
 
+                    case FFMT_CHAR:
+                    case FFMT_SPRITE:
+                        res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor);
+                        break;
+
                     default:
                         dmError("Unsupported output format for bitmap/image conversion.\n");
                         break;