diff tools/lib64gfx.c @ 931:2270d7f3af77

Refactor the DMC64Image handling to be more dynamic, and start work on allowing non 320/160 x 200 formats, and charmode based formats. There is still work to be done, and some problems to sort out.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 25 Feb 2015 19:37:59 +0200
parents db495f421242
children 6320bf08e302
line wrap: on
line diff
--- a/tools/lib64gfx.c	Wed Feb 25 19:32:55 2015 +0200
+++ b/tools/lib64gfx.c	Wed Feb 25 19:37:59 2015 +0200
@@ -12,6 +12,59 @@
 #define BUF_SIZE_GROW      (4*1024)
 
 
+DMC64Image * dmC64ImageAlloc(int width, int height, int ch_width, int ch_height)
+{
+    int i;
+    DMC64Image *img = dmMalloc0(sizeof(DMC64Image));
+
+    if (img == NULL)
+        return NULL;
+
+    img->width     = width;
+    img->height    = height;
+    img->ch_width  = ch_width;
+    img->ch_height = ch_height;
+
+    for (i = 0; i < C64_SCR_MAX_BANK; i++)
+    {
+        if ((img->color[i] = dmMalloc0(ch_width * ch_height)) == NULL)
+            goto err;
+
+        if ((img->bitmap[i] = dmMalloc0(ch_width * ch_height * 8)) == NULL)
+            goto err;
+
+        if ((img->screen[i] = dmMalloc0(ch_width * ch_height)) == NULL)
+            goto err;
+
+        if ((img->charmem[i] = dmMalloc0(C64_MAX_CHARS * C64_CHR_SIZE)) == NULL)
+            goto err;
+    }
+
+    return img;
+
+err:
+    dmC64ImageFree(img);
+    return NULL;
+}
+
+
+void dmC64ImageFree(DMC64Image *img)
+{
+    if (img != NULL)
+    {
+        int i;
+        for (i = 0; i < C64_SCR_MAX_BANK; i++)
+        {
+            dmFree(img->color[i]);
+            dmFree(img->bitmap[i]);
+            dmFree(img->screen[i]);
+        }
+        memset(img, 0, sizeof(DMC64Image));
+        dmFree(img);
+    }
+}
+
+
 char * dmC64GetImageTypeString(char *buf, const size_t len, const int type)
 {
     *buf = 0;
@@ -519,13 +572,11 @@
         }
     },
 
-#define XX2_WIDTH_CH 40
-#define XX2_HEIGHT_CH 10
+#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)
 
-#define XX2_SIZE (XX2_WIDTH_CH * XX2_HEIGHT_CH)
-#define XX2_BSIZE (XX2_SIZE * 8)
-
-#if 0
     {
         D64_FMT_MC, "xx2", "Unknown $2000 format (unpacked)", 0x2000, 4002,
         XX2_WIDTH_CH * 4, XX2_HEIGHT_CH * 8,
@@ -542,20 +593,19 @@
         }
     },
 
-#else
-
+#if 0
     {
-        D64_FMT_MC | D64_FMT_CHAR, "xx2", "Unknown $2000 char format (unpacked)", 0x2000, 4002,
-        XX2_WIDTH_CH * 4, XX2_HEIGHT_CH * 8,
-        XX2_WIDTH_CH    , XX2_HEIGHT_CH,
+        D64_FMT_MC | D64_FMT_CHAR, "xx3", "??? (unpacked)", 0x2000, 0,
+        XX3_WIDTH_CH * 4, XX3_HEIGHT_CH * 8,
+        XX3_WIDTH_CH    , XX3_HEIGHT_CH,
         NULL, NULL,
         NULL, NULL, NULL,
         4,
         {
-            { DT_CHAR_DATA,    0x0000, 0,  XX2_BSIZE, NULL, NULL },
-            { DT_COLOR_RAM,    XX2_BSIZE + XX2_SIZE , 0,  XX2_SIZE, NULL, NULL },
+            { DT_CHAR_DATA,    0x0000, 0,  XX3_BSIZE, NULL, NULL },
+            { DT_COLOR_RAM,    XX3_BSIZE + XX3_SIZE , 0,  XX3_SIZE, NULL, NULL },
 
-            { DT_CHAR_CONFIG,  D64_CHCFG_LINEAR, 0,  XX2_SIZE, NULL, NULL },
+            { DT_CHAR_CONFIG,  D64_CHCFG_LINEAR, 0,  XX3_SIZE, NULL, NULL },
             { DT_COLOR_SET,    1  , 0,  DC_BGCOL, NULL, NULL },
             { DT_COLOR_SET,    3  , 0,  DC_D022, NULL, NULL },
             { DT_COLOR_SET,    4  , 0,  DC_D023, NULL, NULL },
@@ -625,34 +675,51 @@
 }
 
 
-static int dmC64GetOpSize(const DMC64EncDecOp *op, const DMC64ImageFormat *fmt)
+static BOOL dmC64GetOpSize(const DMC64EncDecOp *op, const DMC64ImageFormat *fmt, size_t *size)
 {
-    if (op->size != 0)
-        return op->size;
-
+    BOOL check;
     switch (op->type)
     {
         case DT_SCREEN_RAM:
-            return C64_SCREEN_SIZE;
-
         case DT_COLOR_RAM:
-            return C64_COLOR_SIZE;
+            *size = fmt->ch_height * fmt->ch_width;
+            check = TRUE;
+            break;
 
         case DT_BITMAP:
-            return C64_BITMAP_SIZE;
+            *size = fmt->ch_height * fmt->ch_width * 8;
+            check = TRUE;
+            break;
 
         case DT_EXTRADATA:
-            return C64_SCR_EXTRADATA;
+            *size = C64_SCR_EXTRADATA;
+            check = TRUE;
+            break;
 
         case DT_CHAR_DATA:
-            return C64_MAX_CHARS * C64_CHR_HEIGHT * C64_CHR_WIDTH;
+            *size = C64_MAX_CHARS * C64_CHR_SIZE;
+            check = TRUE;
+            break;
 
         case DT_COLOR_REG:
-            return 1;
+            *size = 1;
+            check = FALSE;
+            break;
 
         default:
-            return 0;
+            *size = 0;
+            check = FALSE;
     }
+
+    if (op->size != 0)
+    {
+        if (check && op->size > *size)
+            return FALSE;
+
+        *size = op->size;
+    }
+
+    return TRUE;
 }
 
 
@@ -671,8 +738,11 @@
     }
 
     // Clear the image structure, set basics
-    memset(img, 0, sizeof(*img));
-    img->type = fmt->type;
+    img->type      = fmt->type;
+    img->width     = fmt->width;
+    img->height    = fmt->height;
+    img->ch_width  = fmt->ch_width;
+    img->ch_height = fmt->ch_height;
 
     // Perform decoding
     for (i = 0; i < fmt->nencdecOps; i++)
@@ -687,7 +757,13 @@
             return res;
 
         // Check size
-        size = dmC64GetOpSize(op, fmt);
+        if (!dmC64GetOpSize(op, fmt, &size))
+        {
+            dmError("Decode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), "
+                "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n",
+                i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size);
+            return DMERR_INVALID_DATA;
+        }
 
         // Do we need to reallocate some more space?
         if (op->offs + size > len)
@@ -706,8 +782,8 @@
             case DT_COLOR_RAM:   memcpy(img->color[op->bank], src, size); break;
             case DT_BITMAP:      memcpy(img->bitmap[op->bank], src, size); break;
             case DT_SCREEN_RAM:  memcpy(img->screen[op->bank], src, size); break;
+            case DT_CHAR_DATA:   memcpy(img->charmem[op->bank], src, size); break;
             case DT_EXTRADATA:   memcpy(img->extradata, src, size); break;
-            case DT_CHAR_DATA:   memcpy(img->charmem, src, size); break;
 
             case DT_COLOR_REG:
                 switch (op->size)
@@ -751,9 +827,9 @@
 
                     case D64_CHCFG_LINEAR:
                         {
-                            size_t bank, offs;
+                            int bank, offs;
                             for (bank = 0; bank < C64_SCR_MAX_BANK; bank++)
-                            for (offs = 0; offs < C64_SCR_SCREEN_SIZE; offs++)
+                            for (offs = 0; offs < fmt->ch_height * fmt->ch_width; offs++)
                                 img->screen[bank][offs] = offs & 0xff;
                         }
                         break;
@@ -831,7 +907,13 @@
             goto error;
 
         // Check size
-        size = dmC64GetOpSize(op, fmt);
+        if (!dmC64GetOpSize(op, fmt, &size))
+        {
+            dmError("Decode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), "
+                "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n",
+                i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size);
+            return DMERR_INVALID_DATA;
+        }
 
         // Do we need to reallocate some more space?
         if (2 + op->offs + size > allocated)
@@ -858,8 +940,8 @@
             case DT_COLOR_RAM:   memcpy(dst, img->color[op->bank], size); break;
             case DT_BITMAP:      memcpy(dst, img->bitmap[op->bank], size); break;
             case DT_SCREEN_RAM:  memcpy(dst, img->screen[op->bank], size); break;
+            case DT_CHAR_DATA:   memcpy(dst, img->charmem[op->bank], size); break;
             case DT_EXTRADATA:   memcpy(dst, img->extradata, size); break;
-            case DT_CHAR_DATA:   memcpy(dst, img->charmem, size); break;
 
             case DT_COLOR_REG:
                 switch (op->size)
@@ -938,37 +1020,39 @@
     if (dst == NULL || src == NULL)
         return DMERR_NULLPTR;
 
-    if (dst->width < 8)
-        return DMERR_INVALID_ARGS;
+    if (dst->width < src->width || dst->height < src->height)
+        return DMERR_INVALID_DATA;
 
-    if (src->type & D64_FMT_CHAR)
-    for (yc = 0; yc < dst->height; yc++)
+    memset(dst->data, 0, dst->size);
+
+    // Perform conversion
+    for (yc = 0; yc < src->height; yc++)
     {
         Uint8 *d = dp;
         const int y = yc / 8, yb = yc & 7;
-        const int scroffsy = y * C64_SCR_CH_WIDTH;
+        const int scroffsy = y * src->ch_width;
         int xc;
 
-        if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
+        if (src->type & D64_FMT_CHAR)
         {
+            // Charmode conversion
+            if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
             // Hi-res charmap
-            for (xc = 0; xc < dst->width; xc++)
+            for (xc = 0; xc < src->width; xc++)
             {
                 const int x = xc / 8;
                 const int scroffs = scroffsy + x;
                 const int chr = src->screen[0][scroffs];
                 const int v = 7 - (xc & 7);
 
-                if ((src->charmem[chr][yb] >> v) & 1)
+                if ((src->charmem[0][chr * C64_CHR_SIZE + yb] >> v) & 1)
                     *d++ = src->color[0][scroffs];
                 else
                     *d++ = src->bgcolor;
             }
-        }
-        else
-        {
+            else
             // Multicolor variants
-            for (xc = 0; xc < dst->width / wdivisor; xc++)
+            for (xc = 0; xc < src->width / wdivisor; xc++)
             {
                 const int x = xc / 4;
                 const int scroffs = scroffsy + x;
@@ -976,7 +1060,7 @@
                 const int v = 6 - ((xc * 2) & 6);
                 Uint8 c;
 
-                switch ((src->charmem[chr][yb] >> v) & 3)
+                switch ((src->charmem[0][chr * C64_CHR_SIZE + yb] >> v) & 3)
                 {
                     case 0: c = src->bgcolor; break;
                     case 1: c = src->d022; break;
@@ -989,22 +1073,14 @@
                     *d++ = c;
             }
         }
-        dp += dst->pitch;
-    }
-    else
-    // Perform generic BITMAP conversion
-    for (yc = 0; yc < dst->height; yc++)
-    {
-        Uint8 *d = dp;
-        const int y = yc / 8, yb = yc & 7;
-        const int scroffsy = y * C64_SCR_CH_WIDTH;
-        const int bmoffsy = y * C64_SCR_WIDTH;
-        int xc;
+        else
+        {
+            // Perform generic BITMAP conversion
+            const int bmoffsy = y * src->width;
 
-        if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
-        {
+            if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
             // Hi-res bitmap
-            for (xc = 0; xc < dst->width; xc++)
+            for (xc = 0; xc < src->width; xc++)
             {
                 const int x = xc / 8;
                 const int scroffs = scroffsy + x;
@@ -1016,11 +1092,9 @@
                 else
                     *d++ = src->screen[0][scroffs] & 15;
             }
-        }
-        else
-        {
-            // Multicolor variants
-            for (xc = 0; xc < dst->width / wdivisor; xc++)
+            else
+            // Multicolor bitmap and variants
+            for (xc = 0; xc < src->width / wdivisor; xc++)
             {
                 const int x = xc / 4;
                 const int scroffs = scroffsy + x;
@@ -1104,10 +1178,13 @@
 }
 
 
-int dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len,
+int dmC64DecodeBMP(DMC64Image **img, const Uint8 *buf, const size_t len,
     const size_t probeOffs, const size_t loadOffs,
     const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced)
 {
+    if (img == NULL)
+        return DMERR_NULLPTR;
+
     // Check for forced format
     if (forced != NULL)
         *fmt = forced;
@@ -1115,18 +1192,26 @@
     {
         // Nope, perform a generic probe
         if (probeOffs >= len)
-            return -200;
+            return DMERR_INVALID_DATA;
 
         if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
-            return -201;
+            return DMERR_INVALID_DATA;
     }
 
     if (loadOffs >= len)
-        return -203;
+        return DMERR_INVALID_ARGS;
+
+    if (*fmt == NULL)
+        return DMERR_INVALID_DATA;
+
+    // Allocate memory
+    if ((*img = dmC64ImageAlloc((*fmt)->width, (*fmt)->height, 
+        (*fmt)->ch_width, (*fmt)->ch_height)) == NULL)
+        return DMERR_MALLOC;
 
     // Decode the bitmap to memory layout
     if ((*fmt)->decode != NULL)
-        return (*fmt)->decode(img, buf + loadOffs, len - loadOffs, *fmt);
+        return (*fmt)->decode(*img, buf + loadOffs, len - loadOffs, *fmt);
     else
-        return dmC64DecodeGenericBMP(img, buf + loadOffs, len - loadOffs, *fmt);
+        return dmC64DecodeGenericBMP(*img, buf + loadOffs, len - loadOffs, *fmt);
 }