Mercurial > hg > dmlib
changeset 447:0e27860ddcfe
Finish initial implementation of IFF ILBM loader. And whoa .. it seems to be working.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 04 Nov 2012 08:40:17 +0200 |
parents | a6d0e101cd16 |
children | f1aab48a76fe |
files | libgfx.c |
diffstat | 1 files changed, 172 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/libgfx.c Sun Nov 04 08:38:25 2012 +0200 +++ b/libgfx.c Sun Nov 04 08:40:17 2012 +0200 @@ -964,7 +964,6 @@ DMIFFBMHD bmhd; int ncolors; DMColor *pal; - DMImage *img; BOOL paletted; } DMIFF; @@ -994,7 +993,11 @@ static BOOL dmSkipIFFChunkRest(FILE *fp, const DMIFFChunk *chunk, const Uint32 used) { if (chunk->size > used) + { + dmMsg(3, "ILBM: Skipping %d bytes (%d of %d consumed)\n", + chunk->size - used, used, chunk->size); return fseeko(fp, chunk->size - used, SEEK_CUR) == 0; + } else return TRUE; } @@ -1018,9 +1021,144 @@ } -int dmDecodeILBMBody(FILE *fp, DMIFF *iff) +static BOOL dmIFFDecodeByteRun1Row(FILE *fp, Uint8 *buf, const size_t bufLen) +{ + size_t offs = 0; + do + { + Sint8 dcount; + Uint8 data; + + if (!dm_fread_byte(fp, (Uint8 *) &dcount)) + return FALSE; + + if (dcount == -128) + { + if (!dm_fread_byte(fp, &data)) + return FALSE; + } + else + if (dcount < 0) + { + int count = (-dcount) + 1; + if (!dm_fread_byte(fp, &data)) + return FALSE; + + while (count-- && offs < bufLen) + buf[offs++] = data; + } + else + { + int count = dcount + 1; + while (count-- && offs < bufLen) + { + if (!dm_fread_byte(fp, &data)) + return FALSE; + + buf[offs++] = data; + } + } + } while (offs < bufLen); + + return TRUE; +} + + +static BOOL dmIFFReadOneRow(FILE *fp, DMIFF *iff, Uint8 *buf, const size_t bufLen) +{ + if (iff->bmhd.compression == IFF_COMP_BYTERUN1) + return dmIFFDecodeByteRun1Row(fp, buf, bufLen); + else + return dm_fread_str(fp, buf, bufLen); +} + + +void dmDecodeBitPlane(Uint8 *dp, Uint8 *src, const int width, const int nplane) +{ + int xc; + for (xc = 0; xc < width; xc++) + { + const Uint8 data = (src[xc / 8] >> (7 - (xc & 7))) & 1; + dp[xc] |= (data << nplane); + } +} + + +int dmDecodeILBMBody(FILE *fp, DMIFF *iff, DMImage **pimg, Uint32 *read) { - return DMERR_OK; + DMImage *img; + Uint8 *buf; + size_t bufLen; + int yc, res = DMERR_OK; + + *read = 0; + + // Allocate image + if ((*pimg = img = dmImageAlloc(iff->bmhd.w, iff->bmhd.h)) == NULL) + return DMERR_MALLOC; + + // Allocate planar decoding buffer + bufLen = ((img->width + 15) / 16) * 2; + if ((buf = dmMalloc(bufLen)) == NULL) + return DMERR_MALLOC; + + dmMsg(2, "ILBM: plane row size %d bytes.\n", bufLen); + + // Decode the chunk + for (yc = 0; yc < img->height; yc++) + { + int plane; + const int nplanes = iff->bmhd.nplanes; + Uint8 *dp = img->data + (yc * img->pitch); + + memset(dp, 0, img->pitch); + + for (plane = 0; plane < nplanes; plane++) + { + // Decompress or read data + if (!dmIFFReadOneRow(fp, iff, buf, bufLen)) + { + dmError("ILBM: Error in reading image plane #%d.\n", plane); + res = DMERR_FREAD; + goto error; + } + + // Decode bitplane + dmDecodeBitPlane(dp, buf, img->width, plane); + + *read += bufLen; + } + + // Read mask data + if (iff->bmhd.masking == IFF_MASK_HAS_MASK) + { + int xc; + + // Decompress or read data + if (!dmIFFReadOneRow(fp, iff, buf, bufLen)) + { + dmError("ILBM: Error in reading mask plane.\n"); + res = DMERR_FREAD; + goto error; + } + + // Decode mask + for (xc = 0; xc < img->width; xc++) + { + const Uint8 data = (buf[xc / 8] >> (7 - (xc & 7))) & 1; + + // Black out any pixels with mask bit 0 + if (!data) + dp[xc] = 0; + } + + *read += bufLen; + } + } + +error: + dmFree(buf); + return res; } @@ -1029,6 +1167,7 @@ Uint32 idILBM; DMIFFChunk chunk; DMIFF iff; + Uint32 read; BOOL parsed = FALSE; int i, res = DMERR_OK; @@ -1062,9 +1201,11 @@ switch (chunk.id) { case IFF_ID_BMHD: + // Check for multiple occurences of BMHD if (!dmCheckIFFChunk(&iff.chBMHD, &chunk, FALSE, sizeof(iff.bmhd))) return DMERR_FREAD; + // Read BMHD data if (!dm_fread_be16(fp, &iff.bmhd.w) || !dm_fread_be16(fp, &iff.bmhd.h) || !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.x) || @@ -1083,8 +1224,20 @@ return DMERR_FREAD; } dmMsg(2, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n", - iff.bmhd.w, iff.bmhd.h, iff.bmhd.x, iff.bmhd.y, iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking); + iff.bmhd.w, iff.bmhd.h, iff.bmhd.x, iff.bmhd.y, + iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking); + // Sanity check + if (iff.bmhd.nplanes < 1 || iff.bmhd.nplanes > 8 || + (iff.bmhd.compression != IFF_COMP_NONE && + iff.bmhd.compression != IFF_COMP_BYTERUN1) || + (iff.bmhd.masking != IFF_MASK_NONE && + iff.bmhd.masking != IFF_MASK_HAS_MASK)) + { + dmError("ILBM: Unsupported features, refusing to load.\n"); + return DMERR_INVALID_DATA; + } + if (!dmSkipIFFChunkRest(fp, &chunk, sizeof(iff.bmhd))) return DMERR_FREAD; break; @@ -1138,9 +1291,11 @@ break; case IFF_ID_BODY: + // Check for multiple occurences of CMAP if (!dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1)) return DMERR_FREAD; + // Check for sanity if (!iff.chBMHD.count) { dmError("ILBM: BODY chunk before BMHD?\n"); @@ -1148,13 +1303,14 @@ } dmMsg(2, "ILBM: BODY chunk size %d bytes\n", chunk.size); + + // Decode the body + if ((res = dmDecodeILBMBody(fp, &iff, pimg, &read)) != DMERR_OK) + return res; - if (fseeko(fp, chunk.size, SEEK_CUR) != 0) - { - dmError("ILBM: Error skipping in file."); + if (!dmSkipIFFChunkRest(fp, &chunk, read)) return DMERR_FREAD; - } - + if (iff.chCMAP.count) parsed = TRUE; break; @@ -1177,6 +1333,13 @@ fgetc(fp); } + // Set colormap after finishing + if (iff.pal != NULL && iff.ncolors > 0 && *pimg != NULL) + { + (*pimg)->ncolors = iff.ncolors; + (*pimg)->pal = iff.pal; + } + return res; }