changeset 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 efbad8817b79
children 6320bf08e302
files tools/gfxconv.c tools/lib64gfx.c tools/lib64gfx.h tools/view64.c
diffstat 4 files changed, 179 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/tools/gfxconv.c	Wed Feb 25 19:32:55 2015 +0200
+++ b/tools/gfxconv.c	Wed Feb 25 19:37:59 2015 +0200
@@ -1556,7 +1556,7 @@
 {
     FILE *inFile;
     const DMC64ImageFormat *cfmt;
-    DMC64Image cimage;
+    DMC64Image *cimage = NULL;
     Uint8 *dataBuf = NULL;
     size_t dataSize;
     int i;
@@ -1709,7 +1709,7 @@
                 switch (optOutFormat)
                 {
                     case FFMT_IMAGE:
-                        res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, FALSE);
+                        res = dmC64ConvertBMP2Image(&outImage, cimage, cfmt, FALSE);
 
                         if (res != DMERR_OK || outImage == NULL)
                         {
@@ -1722,12 +1722,12 @@
 
 
                     case FFMT_BITMAP:
-                        res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE);
+                        res = dmWriteBitmap(optOutFilename, cimage, optOutSubFormat, TRUE);
                         break;
 
                     case FFMT_CHAR:
                     case FFMT_SPRITE:
-                        res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE);
+                        res = dmC64ConvertBMP2Image(&outImage, cimage, cfmt, TRUE);
 
                         if (res != DMERR_OK || outImage == NULL)
                         {
@@ -1803,6 +1803,7 @@
 
 error:
     dmFree(dataBuf);
+    dmFree(cimage);
     return -3;
     exit(3);
 }
--- 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);
 }
--- a/tools/lib64gfx.h	Wed Feb 25 19:32:55 2015 +0200
+++ b/tools/lib64gfx.h	Wed Feb 25 19:37:59 2015 +0200
@@ -133,14 +133,17 @@
         laceBank1,  // Interlace video bank indices
         laceBank2;
 
+    int width, height; // Width and height in pixels
+    int ch_width, ch_height; // Width and height in charblocks
+
     Uint8
-        color[C64_SCR_MAX_BANK][C64_SCR_COLOR_SIZE],
-        bitmap[C64_SCR_MAX_BANK][C64_SCR_BITMAP_SIZE],
-        screen[C64_SCR_MAX_BANK][C64_SCR_SCREEN_SIZE],
+        *color[C64_SCR_MAX_BANK],
+        *bitmap[C64_SCR_MAX_BANK],
+        *screen[C64_SCR_MAX_BANK],
+        *charmem[C64_SCR_MAX_BANK],
         extradata[C64_SCR_EXTRADATA],
         d020, bgcolor, d022, d023, d024;
 
-    Uint8 charmem[C64_MAX_CHARS][C64_CHR_HEIGHT * C64_CHR_WIDTH];
     DMC64Sprite sprites[C64_MAX_SPRITES];
 } DMC64Image;
 
@@ -206,6 +209,10 @@
 extern const int         ndmC64ImageFormats;
 
 
+DMC64Image *dmC64ImageAlloc(int width, int height, int ch_width, int ch_height);
+void      dmC64ImageFree(DMC64Image *img);
+
+
 char *    dmC64GetImageTypeString(char *buf, const size_t len, const int type);
 int       dmC64ConvertCSDataToImage(DMImage *img, int xoffs, int yoffs, const Uint8 *inBuf, int width, int height, BOOL multicolor, int *colors);
 
@@ -215,7 +222,7 @@
 
 int       dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const BOOL doubleMC);
 int       dmC64ProbeBMP(const Uint8 *buf, const size_t len, const DMC64ImageFormat **fmt);
-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);
+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);
 
 
 #ifdef __cplusplus
--- a/tools/view64.c	Wed Feb 25 19:32:55 2015 +0200
+++ b/tools/view64.c	Wed Feb 25 19:37:59 2015 +0200
@@ -157,7 +157,7 @@
     DMImage bmap;
     BOOL initSDL = FALSE, exitFlag, needRedraw;
     const DMC64ImageFormat *fmt = NULL, *forced;
-    DMC64Image image;
+    DMC64Image *cimage = NULL;
     char *windowTitle;
     Uint8 *dataBuf = NULL;
     size_t dataSize;
@@ -194,7 +194,7 @@
     else
         forced = NULL;
 
-    ret = dmC64DecodeBMP(&image, dataBuf, dataSize, 0, 2, &fmt, forced);
+    ret = dmC64DecodeBMP(&cimage, dataBuf, dataSize, 0, 2, &fmt, forced);
     if (forced == NULL && fmt != NULL)
     {
         dmMsg(0,"Probed %s format image, type %d, %s\n",
@@ -231,6 +231,7 @@
     SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
 
     // Convert bitmap (this is a bit ugly and lazy here)
+    bmap.size = surf->pitch * surf->h;
     bmap.data = surf->pixels;
     bmap.pitch = surf->pitch;
     bmap.width = surf->w;
@@ -238,9 +239,9 @@
     bmap.constpal = TRUE;
 
     if (fmt->convertFrom != NULL)
-        ret = fmt->convertFrom(&bmap, &image, TRUE);
+        ret = fmt->convertFrom(&bmap, cimage, TRUE);
     else
-        ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE);
+        ret = dmC64ConvertGenericBMP2Image(&bmap, cimage, TRUE);
 
 
     // Set window title and caption