Mercurial > hg > dmlib
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) |