comparison libgfx.c @ 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 1d65efb29986
children f1aab48a76fe
comparison
equal deleted inserted replaced
446:a6d0e101cd16 447:0e27860ddcfe
962 { 962 {
963 DMIFFChunk chBMHD, chCMAP, chBODY; 963 DMIFFChunk chBMHD, chCMAP, chBODY;
964 DMIFFBMHD bmhd; 964 DMIFFBMHD bmhd;
965 int ncolors; 965 int ncolors;
966 DMColor *pal; 966 DMColor *pal;
967 DMImage *img;
968 BOOL paletted; 967 BOOL paletted;
969 } DMIFF; 968 } DMIFF;
970 969
971 970
972 static BOOL dmReadIFFChunk(FILE *fp, DMIFFChunk *chunk) 971 static BOOL dmReadIFFChunk(FILE *fp, DMIFFChunk *chunk)
992 } 991 }
993 992
994 static BOOL dmSkipIFFChunkRest(FILE *fp, const DMIFFChunk *chunk, const Uint32 used) 993 static BOOL dmSkipIFFChunkRest(FILE *fp, const DMIFFChunk *chunk, const Uint32 used)
995 { 994 {
996 if (chunk->size > used) 995 if (chunk->size > used)
996 {
997 dmMsg(3, "ILBM: Skipping %d bytes (%d of %d consumed)\n",
998 chunk->size - used, used, chunk->size);
997 return fseeko(fp, chunk->size - used, SEEK_CUR) == 0; 999 return fseeko(fp, chunk->size - used, SEEK_CUR) == 0;
1000 }
998 else 1001 else
999 return TRUE; 1002 return TRUE;
1000 } 1003 }
1001 1004
1002 static BOOL dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk, 1005 static BOOL dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk,
1016 1019
1017 return TRUE; 1020 return TRUE;
1018 } 1021 }
1019 1022
1020 1023
1021 int dmDecodeILBMBody(FILE *fp, DMIFF *iff) 1024 static BOOL dmIFFDecodeByteRun1Row(FILE *fp, Uint8 *buf, const size_t bufLen)
1022 { 1025 {
1023 return DMERR_OK; 1026 size_t offs = 0;
1027 do
1028 {
1029 Sint8 dcount;
1030 Uint8 data;
1031
1032 if (!dm_fread_byte(fp, (Uint8 *) &dcount))
1033 return FALSE;
1034
1035 if (dcount == -128)
1036 {
1037 if (!dm_fread_byte(fp, &data))
1038 return FALSE;
1039 }
1040 else
1041 if (dcount < 0)
1042 {
1043 int count = (-dcount) + 1;
1044 if (!dm_fread_byte(fp, &data))
1045 return FALSE;
1046
1047 while (count-- && offs < bufLen)
1048 buf[offs++] = data;
1049 }
1050 else
1051 {
1052 int count = dcount + 1;
1053 while (count-- && offs < bufLen)
1054 {
1055 if (!dm_fread_byte(fp, &data))
1056 return FALSE;
1057
1058 buf[offs++] = data;
1059 }
1060 }
1061 } while (offs < bufLen);
1062
1063 return TRUE;
1064 }
1065
1066
1067 static BOOL dmIFFReadOneRow(FILE *fp, DMIFF *iff, Uint8 *buf, const size_t bufLen)
1068 {
1069 if (iff->bmhd.compression == IFF_COMP_BYTERUN1)
1070 return dmIFFDecodeByteRun1Row(fp, buf, bufLen);
1071 else
1072 return dm_fread_str(fp, buf, bufLen);
1073 }
1074
1075
1076 void dmDecodeBitPlane(Uint8 *dp, Uint8 *src, const int width, const int nplane)
1077 {
1078 int xc;
1079 for (xc = 0; xc < width; xc++)
1080 {
1081 const Uint8 data = (src[xc / 8] >> (7 - (xc & 7))) & 1;
1082 dp[xc] |= (data << nplane);
1083 }
1084 }
1085
1086
1087 int dmDecodeILBMBody(FILE *fp, DMIFF *iff, DMImage **pimg, Uint32 *read)
1088 {
1089 DMImage *img;
1090 Uint8 *buf;
1091 size_t bufLen;
1092 int yc, res = DMERR_OK;
1093
1094 *read = 0;
1095
1096 // Allocate image
1097 if ((*pimg = img = dmImageAlloc(iff->bmhd.w, iff->bmhd.h)) == NULL)
1098 return DMERR_MALLOC;
1099
1100 // Allocate planar decoding buffer
1101 bufLen = ((img->width + 15) / 16) * 2;
1102 if ((buf = dmMalloc(bufLen)) == NULL)
1103 return DMERR_MALLOC;
1104
1105 dmMsg(2, "ILBM: plane row size %d bytes.\n", bufLen);
1106
1107 // Decode the chunk
1108 for (yc = 0; yc < img->height; yc++)
1109 {
1110 int plane;
1111 const int nplanes = iff->bmhd.nplanes;
1112 Uint8 *dp = img->data + (yc * img->pitch);
1113
1114 memset(dp, 0, img->pitch);
1115
1116 for (plane = 0; plane < nplanes; plane++)
1117 {
1118 // Decompress or read data
1119 if (!dmIFFReadOneRow(fp, iff, buf, bufLen))
1120 {
1121 dmError("ILBM: Error in reading image plane #%d.\n", plane);
1122 res = DMERR_FREAD;
1123 goto error;
1124 }
1125
1126 // Decode bitplane
1127 dmDecodeBitPlane(dp, buf, img->width, plane);
1128
1129 *read += bufLen;
1130 }
1131
1132 // Read mask data
1133 if (iff->bmhd.masking == IFF_MASK_HAS_MASK)
1134 {
1135 int xc;
1136
1137 // Decompress or read data
1138 if (!dmIFFReadOneRow(fp, iff, buf, bufLen))
1139 {
1140 dmError("ILBM: Error in reading mask plane.\n");
1141 res = DMERR_FREAD;
1142 goto error;
1143 }
1144
1145 // Decode mask
1146 for (xc = 0; xc < img->width; xc++)
1147 {
1148 const Uint8 data = (buf[xc / 8] >> (7 - (xc & 7))) & 1;
1149
1150 // Black out any pixels with mask bit 0
1151 if (!data)
1152 dp[xc] = 0;
1153 }
1154
1155 *read += bufLen;
1156 }
1157 }
1158
1159 error:
1160 dmFree(buf);
1161 return res;
1024 } 1162 }
1025 1163
1026 1164
1027 int dmReadILBMImageFILE(FILE *fp, DMImage **pimg) 1165 int dmReadILBMImageFILE(FILE *fp, DMImage **pimg)
1028 { 1166 {
1029 Uint32 idILBM; 1167 Uint32 idILBM;
1030 DMIFFChunk chunk; 1168 DMIFFChunk chunk;
1031 DMIFF iff; 1169 DMIFF iff;
1170 Uint32 read;
1032 BOOL parsed = FALSE; 1171 BOOL parsed = FALSE;
1033 int i, res = DMERR_OK; 1172 int i, res = DMERR_OK;
1034 1173
1035 memset(&iff, 0, sizeof(iff)); 1174 memset(&iff, 0, sizeof(iff));
1036 1175
1060 } 1199 }
1061 1200
1062 switch (chunk.id) 1201 switch (chunk.id)
1063 { 1202 {
1064 case IFF_ID_BMHD: 1203 case IFF_ID_BMHD:
1204 // Check for multiple occurences of BMHD
1065 if (!dmCheckIFFChunk(&iff.chBMHD, &chunk, FALSE, sizeof(iff.bmhd))) 1205 if (!dmCheckIFFChunk(&iff.chBMHD, &chunk, FALSE, sizeof(iff.bmhd)))
1066 return DMERR_FREAD; 1206 return DMERR_FREAD;
1067 1207
1208 // Read BMHD data
1068 if (!dm_fread_be16(fp, &iff.bmhd.w) || 1209 if (!dm_fread_be16(fp, &iff.bmhd.w) ||
1069 !dm_fread_be16(fp, &iff.bmhd.h) || 1210 !dm_fread_be16(fp, &iff.bmhd.h) ||
1070 !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.x) || 1211 !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.x) ||
1071 !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.y) || 1212 !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.y) ||
1072 !dm_fread_byte(fp, &iff.bmhd.nplanes) || 1213 !dm_fread_byte(fp, &iff.bmhd.nplanes) ||
1081 { 1222 {
1082 dmError("ILBM: Error reading BMHD chunk.\n"); 1223 dmError("ILBM: Error reading BMHD chunk.\n");
1083 return DMERR_FREAD; 1224 return DMERR_FREAD;
1084 } 1225 }
1085 dmMsg(2, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n", 1226 dmMsg(2, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n",
1086 iff.bmhd.w, iff.bmhd.h, iff.bmhd.x, iff.bmhd.y, iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking); 1227 iff.bmhd.w, iff.bmhd.h, iff.bmhd.x, iff.bmhd.y,
1228 iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking);
1087 1229
1230 // Sanity check
1231 if (iff.bmhd.nplanes < 1 || iff.bmhd.nplanes > 8 ||
1232 (iff.bmhd.compression != IFF_COMP_NONE &&
1233 iff.bmhd.compression != IFF_COMP_BYTERUN1) ||
1234 (iff.bmhd.masking != IFF_MASK_NONE &&
1235 iff.bmhd.masking != IFF_MASK_HAS_MASK))
1236 {
1237 dmError("ILBM: Unsupported features, refusing to load.\n");
1238 return DMERR_INVALID_DATA;
1239 }
1240
1088 if (!dmSkipIFFChunkRest(fp, &chunk, sizeof(iff.bmhd))) 1241 if (!dmSkipIFFChunkRest(fp, &chunk, sizeof(iff.bmhd)))
1089 return DMERR_FREAD; 1242 return DMERR_FREAD;
1090 break; 1243 break;
1091 1244
1092 1245
1136 if (iff.chBMHD.count && iff.chBODY.count) 1289 if (iff.chBMHD.count && iff.chBODY.count)
1137 parsed = TRUE; 1290 parsed = TRUE;
1138 break; 1291 break;
1139 1292
1140 case IFF_ID_BODY: 1293 case IFF_ID_BODY:
1294 // Check for multiple occurences of CMAP
1141 if (!dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1)) 1295 if (!dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1))
1142 return DMERR_FREAD; 1296 return DMERR_FREAD;
1143 1297
1298 // Check for sanity
1144 if (!iff.chBMHD.count) 1299 if (!iff.chBMHD.count)
1145 { 1300 {
1146 dmError("ILBM: BODY chunk before BMHD?\n"); 1301 dmError("ILBM: BODY chunk before BMHD?\n");
1147 return DMERR_INVALID_DATA; 1302 return DMERR_INVALID_DATA;
1148 } 1303 }
1149 1304
1150 dmMsg(2, "ILBM: BODY chunk size %d bytes\n", chunk.size); 1305 dmMsg(2, "ILBM: BODY chunk size %d bytes\n", chunk.size);
1151 1306
1152 if (fseeko(fp, chunk.size, SEEK_CUR) != 0) 1307 // Decode the body
1153 { 1308 if ((res = dmDecodeILBMBody(fp, &iff, pimg, &read)) != DMERR_OK)
1154 dmError("ILBM: Error skipping in file."); 1309 return res;
1310
1311 if (!dmSkipIFFChunkRest(fp, &chunk, read))
1155 return DMERR_FREAD; 1312 return DMERR_FREAD;
1156 } 1313
1157
1158 if (iff.chCMAP.count) 1314 if (iff.chCMAP.count)
1159 parsed = TRUE; 1315 parsed = TRUE;
1160 break; 1316 break;
1161 1317
1162 default: 1318 default:
1175 1331
1176 if (chunk.size & 1) 1332 if (chunk.size & 1)
1177 fgetc(fp); 1333 fgetc(fp);
1178 } 1334 }
1179 1335
1336 // Set colormap after finishing
1337 if (iff.pal != NULL && iff.ncolors > 0 && *pimg != NULL)
1338 {
1339 (*pimg)->ncolors = iff.ncolors;
1340 (*pimg)->pal = iff.pal;
1341 }
1342
1180 return res; 1343 return res;
1181 } 1344 }
1182 1345
1183 1346
1184 int dmReadILBMImage(const char *filename, DMImage **pimg) 1347 int dmReadILBMImage(const char *filename, DMImage **pimg)