Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
| 3 | * described in COPYING.txt. |
||
| 4 | * Portions of this file are copyright Parallax Software and licensed |
||
| 5 | * according to the Parallax license below. |
||
| 6 | * See COPYING.txt for license details. |
||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
| 9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
| 12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
| 14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
| 17 | COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | |||
| 20 | /* |
||
| 21 | * |
||
| 22 | * Routines for reading and writing IFF files |
||
| 23 | * |
||
| 24 | */ |
||
| 25 | |||
| 26 | #define COMPRESS 1 //do the RLE or not? (for debugging mostly) |
||
| 27 | #define WRITE_TINY 0 //should we write a TINY chunk? |
||
| 28 | |||
| 29 | #define MIN_COMPRESS_WIDTH 65 //don't compress if less than this wide |
||
| 30 | |||
| 31 | #include <stdio.h> |
||
| 32 | #include <stdlib.h> |
||
| 33 | #include <string.h> |
||
| 34 | |||
| 35 | #include "u_mem.h" |
||
| 36 | #include "iff.h" |
||
| 37 | #include "dxxerror.h" |
||
| 38 | #include "makesig.h" |
||
| 39 | #include "physfsx.h" |
||
| 40 | #include "gr.h" |
||
| 41 | |||
| 42 | #include "dxxsconf.h" |
||
| 43 | #include "compiler-range_for.h" |
||
| 44 | #include "partial_range.h" |
||
| 45 | #include <memory> |
||
| 46 | |||
| 47 | //Internal constants and structures for this library |
||
| 48 | |||
| 49 | //Type values for bitmaps |
||
| 50 | #define TYPE_PBM 0 |
||
| 51 | #define TYPE_ILBM 1 |
||
| 52 | |||
| 53 | //Compression types |
||
| 54 | #define cmpNone 0 |
||
| 55 | #define cmpByteRun1 1 |
||
| 56 | |||
| 57 | //Masking types |
||
| 58 | #define mskNone 0 |
||
| 59 | #define mskHasMask 1 |
||
| 60 | #define mskHasTransparentColor 2 |
||
| 61 | |||
| 62 | //structure of the header in the file |
||
| 63 | struct iff_bitmap_header : prohibit_void_ptr<iff_bitmap_header> |
||
| 64 | { |
||
| 65 | short w,h; //width and height of this bitmap |
||
| 66 | short x,y; //generally unused |
||
| 67 | short type; //see types above |
||
| 68 | short transparentcolor; //which color is transparent (if any) |
||
| 69 | short pagewidth,pageheight; //width & height of source screen |
||
| 70 | sbyte nplanes; //number of planes (8 for 256 color image) |
||
| 71 | sbyte masking,compression; //see constants above |
||
| 72 | sbyte xaspect,yaspect; //aspect ratio (usually 5/6) |
||
| 73 | palette_array_t palette; //the palette for this bitmap |
||
| 74 | short row_size; //offset to next row |
||
| 75 | RAIIdmem<uint8_t[]> raw_data; //ptr to array of data |
||
| 76 | }; |
||
| 77 | |||
| 78 | ubyte iff_transparent_color; |
||
| 79 | ubyte iff_has_transparency; // 0=no transparency, 1=iff_transparent_color is valid |
||
| 80 | |||
| 81 | #define form_sig MAKE_SIG('F','O','R','M') |
||
| 82 | #define ilbm_sig MAKE_SIG('I','L','B','M') |
||
| 83 | #define body_sig MAKE_SIG('B','O','D','Y') |
||
| 84 | #define pbm_sig MAKE_SIG('P','B','M',' ') |
||
| 85 | #define bmhd_sig MAKE_SIG('B','M','H','D') |
||
| 86 | #define anhd_sig MAKE_SIG('A','N','H','D') |
||
| 87 | #define cmap_sig MAKE_SIG('C','M','A','P') |
||
| 88 | #define tiny_sig MAKE_SIG('T','I','N','Y') |
||
| 89 | #define anim_sig MAKE_SIG('A','N','I','M') |
||
| 90 | #define dlta_sig MAKE_SIG('D','L','T','A') |
||
| 91 | |||
| 92 | static int32_t get_sig(PHYSFS_File *f) |
||
| 93 | { |
||
| 94 | int s; |
||
| 95 | |||
| 96 | PHYSFS_readSBE32(f, &s); |
||
| 97 | return s; |
||
| 98 | } |
||
| 99 | |||
| 100 | #define put_sig(sig, f) PHYSFS_writeSBE32(f, sig) |
||
| 101 | |||
| 102 | static int parse_bmhd(PHYSFS_File *ifile,long len,iff_bitmap_header *bmheader) |
||
| 103 | { |
||
| 104 | len++; /* so no "parm not used" warning */ |
||
| 105 | |||
| 106 | // debug("parsing bmhd len=%ld\n",len); |
||
| 107 | |||
| 108 | PHYSFS_readSBE16(ifile, &bmheader->w); |
||
| 109 | PHYSFS_readSBE16(ifile, &bmheader->h); |
||
| 110 | PHYSFS_readSBE16(ifile, &bmheader->x); |
||
| 111 | PHYSFS_readSBE16(ifile, &bmheader->y); |
||
| 112 | |||
| 113 | bmheader->nplanes = PHYSFSX_readByte(ifile); |
||
| 114 | bmheader->masking = PHYSFSX_readByte(ifile); |
||
| 115 | bmheader->compression = PHYSFSX_readByte(ifile); |
||
| 116 | PHYSFSX_readByte(ifile); /* skip pad */ |
||
| 117 | |||
| 118 | PHYSFS_readSBE16(ifile, &bmheader->transparentcolor); |
||
| 119 | bmheader->xaspect = PHYSFSX_readByte(ifile); |
||
| 120 | bmheader->yaspect = PHYSFSX_readByte(ifile); |
||
| 121 | |||
| 122 | PHYSFS_readSBE16(ifile, &bmheader->pagewidth); |
||
| 123 | PHYSFS_readSBE16(ifile, &bmheader->pageheight); |
||
| 124 | |||
| 125 | iff_transparent_color = bmheader->transparentcolor; |
||
| 126 | |||
| 127 | iff_has_transparency = 0; |
||
| 128 | |||
| 129 | if (bmheader->masking == mskHasTransparentColor) |
||
| 130 | iff_has_transparency = 1; |
||
| 131 | |||
| 132 | else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask) |
||
| 133 | return IFF_UNKNOWN_MASK; |
||
| 134 | |||
| 135 | // debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y); |
||
| 136 | // debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor); |
||
| 137 | |||
| 138 | return IFF_NO_ERROR; |
||
| 139 | } |
||
| 140 | |||
| 141 | |||
| 142 | // the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data |
||
| 143 | namespace dsx { |
||
| 144 | static int parse_body(PHYSFS_File *ifile,long len,iff_bitmap_header *bmheader) |
||
| 145 | { |
||
| 146 | auto p = bmheader->raw_data.get(); |
||
| 147 | int width,depth; |
||
| 148 | signed char n; |
||
| 149 | int nn,wid_cnt,end_cnt,plane; |
||
| 150 | unsigned char *data_end; |
||
| 151 | int end_pos; |
||
| 152 | #ifndef NDEBUG |
||
| 153 | int row_count=0; |
||
| 154 | #endif |
||
| 155 | |||
| 156 | width=0; |
||
| 157 | depth=0; |
||
| 158 | |||
| 159 | end_pos = PHYSFS_tell(ifile) + len; |
||
| 160 | if (len&1) |
||
| 161 | end_pos++; |
||
| 162 | |||
| 163 | if (bmheader->type == TYPE_PBM) { |
||
| 164 | width=bmheader->w; |
||
| 165 | depth=1; |
||
| 166 | } else if (bmheader->type == TYPE_ILBM) { |
||
| 167 | width = (bmheader->w+7)/8; |
||
| 168 | depth=bmheader->nplanes; |
||
| 169 | } |
||
| 170 | |||
| 171 | end_cnt = (width&1)?-1:0; |
||
| 172 | |||
| 173 | data_end = p + width*bmheader->h*depth; |
||
| 174 | |||
| 175 | if (bmheader->compression == cmpNone) { /* no compression */ |
||
| 176 | int y; |
||
| 177 | |||
| 178 | for (y=bmheader->h;y;y--) { |
||
| 179 | PHYSFS_read(ifile, p, width, depth); |
||
| 180 | p += bmheader->w; |
||
| 181 | |||
| 182 | if (bmheader->masking == mskHasMask) |
||
| 183 | PHYSFSX_fseek(ifile, width, SEEK_CUR); //skip mask! |
||
| 184 | |||
| 185 | if (bmheader->w & 1) PHYSFSX_fgetc(ifile); |
||
| 186 | } |
||
| 187 | |||
| 188 | //cnt = len - bmheader->h * ((bmheader->w+1)&~1); |
||
| 189 | |||
| 190 | } |
||
| 191 | else if (bmheader->compression == cmpByteRun1) |
||
| 192 | for (wid_cnt=width,plane=0; PHYSFS_tell(ifile) < end_pos && p<data_end;) { |
||
| 193 | unsigned char c; |
||
| 194 | |||
| 195 | if (wid_cnt == end_cnt) { |
||
| 196 | wid_cnt = width; |
||
| 197 | plane++; |
||
| 198 | if ((bmheader->masking == mskHasMask && plane==depth+1) || |
||
| 199 | (bmheader->masking != mskHasMask && plane==depth)) |
||
| 200 | plane=0; |
||
| 201 | } |
||
| 202 | |||
| 203 | Assert(wid_cnt > end_cnt); |
||
| 204 | |||
| 205 | n=PHYSFSX_fgetc(ifile); |
||
| 206 | |||
| 207 | if (n >= 0) { // copy next n+1 bytes from source, they are not compressed |
||
| 208 | nn = static_cast<int>(n)+1; |
||
| 209 | wid_cnt -= nn; |
||
| 210 | if (wid_cnt==-1) {--nn; Assert(width&1);} |
||
| 211 | if (plane==depth) //masking row |
||
| 212 | PHYSFSX_fseek(ifile, nn, SEEK_CUR); |
||
| 213 | else |
||
| 214 | { |
||
| 215 | PHYSFS_read(ifile, p, nn, 1); |
||
| 216 | p += nn; |
||
| 217 | } |
||
| 218 | if (wid_cnt==-1) PHYSFSX_fseek(ifile, 1, SEEK_CUR); |
||
| 219 | } |
||
| 220 | else if (n>=-127) { // next -n + 1 bytes are following byte |
||
| 221 | c=PHYSFSX_fgetc(ifile); |
||
| 222 | const int negative_n = -n; |
||
| 223 | nn = negative_n + 1; |
||
| 224 | wid_cnt -= nn; |
||
| 225 | if (wid_cnt==-1) {--nn; Assert(width&1);} |
||
| 226 | if (plane!=depth) //not masking row |
||
| 227 | {memset(p,c,nn); p+=nn;} |
||
| 228 | } |
||
| 229 | |||
| 230 | #ifndef NDEBUG |
||
| 231 | if ((p - bmheader->raw_data.get()) % width == 0) |
||
| 232 | row_count++; |
||
| 233 | |||
| 234 | Assert((p - bmheader->raw_data.get()) - (width*row_count) < width); |
||
| 235 | #endif |
||
| 236 | |||
| 237 | } |
||
| 238 | |||
| 239 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 240 | if (bmheader->masking==mskHasMask && p==data_end && PHYSFS_tell(ifile)==end_pos-2) //I don't know why... |
||
| 241 | PHYSFSX_fseek(ifile, 1, SEEK_CUR); //...but if I do this it works |
||
| 242 | |||
| 243 | if (p==data_end && PHYSFS_tell(ifile)==end_pos-1) //must be a pad byte |
||
| 244 | //ignore = PHYSFSX_fgetc(ifile); //get pad byte |
||
| 245 | PHYSFSX_fseek(ifile, 1, SEEK_CUR); |
||
| 246 | else |
||
| 247 | if (PHYSFS_tell(ifile)!=end_pos || p!=data_end) { |
||
| 248 | // debug("IFF Error: p=%x, data_end=%x, cnt=%d\n",p,data_end,cnt); |
||
| 249 | return IFF_CORRUPT; |
||
| 250 | } |
||
| 251 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 252 | if (p!=data_end) //if we don't have the whole bitmap... |
||
| 253 | return IFF_CORRUPT; //...the give an error |
||
| 254 | |||
| 255 | //Pretend we read the whole chuck, because if we didn't, it's because |
||
| 256 | //we didn't read the last mask like or the last rle record for padding |
||
| 257 | //or whatever and it's not important, because we check to make sure |
||
| 258 | //we got the while bitmap, and that's what really counts. |
||
| 259 | #endif |
||
| 260 | |||
| 261 | return IFF_NO_ERROR; |
||
| 262 | } |
||
| 263 | } |
||
| 264 | |||
| 265 | //modify passed bitmap |
||
| 266 | static int parse_delta(PHYSFS_File *ifile,long len,iff_bitmap_header *bmheader) |
||
| 267 | { |
||
| 268 | auto p = bmheader->raw_data.get(); |
||
| 269 | long chunk_end = PHYSFS_tell(ifile) + len; |
||
| 270 | |||
| 271 | PHYSFSX_fseek(ifile, 4, SEEK_CUR); //longword, seems to be equal to 4. Don't know what it is |
||
| 272 | |||
| 273 | for (int y=0;y<bmheader->h;y++) { |
||
| 274 | ubyte n_items; |
||
| 275 | int cnt = bmheader->w; |
||
| 276 | ubyte code; |
||
| 277 | |||
| 278 | n_items = PHYSFSX_readByte(ifile); |
||
| 279 | |||
| 280 | while (n_items--) { |
||
| 281 | |||
| 282 | code = PHYSFSX_readByte(ifile); |
||
| 283 | |||
| 284 | if (code==0) { //repeat |
||
| 285 | ubyte rep,val; |
||
| 286 | |||
| 287 | rep = PHYSFSX_readByte(ifile); |
||
| 288 | val = PHYSFSX_readByte(ifile); |
||
| 289 | |||
| 290 | cnt -= rep; |
||
| 291 | if (cnt==-1) |
||
| 292 | rep--; |
||
| 293 | while (rep--) |
||
| 294 | *p++ = val; |
||
| 295 | } |
||
| 296 | else if (code > 0x80) { //skip |
||
| 297 | cnt -= (code-0x80); |
||
| 298 | p += (code-0x80); |
||
| 299 | if (cnt==-1) |
||
| 300 | p--; |
||
| 301 | } |
||
| 302 | else { //literal |
||
| 303 | cnt -= code; |
||
| 304 | if (cnt==-1) |
||
| 305 | code--; |
||
| 306 | |||
| 307 | while (code--) |
||
| 308 | *p++ = PHYSFSX_readByte(ifile); |
||
| 309 | |||
| 310 | if (cnt==-1) |
||
| 311 | PHYSFSX_readByte(ifile); |
||
| 312 | } |
||
| 313 | |||
| 314 | } |
||
| 315 | |||
| 316 | if (cnt == -1) { |
||
| 317 | if (!bmheader->w) |
||
| 318 | return IFF_CORRUPT; |
||
| 319 | } |
||
| 320 | else if (cnt) |
||
| 321 | return IFF_CORRUPT; |
||
| 322 | } |
||
| 323 | |||
| 324 | if (PHYSFS_tell(ifile) == chunk_end-1) //pad |
||
| 325 | PHYSFSX_fseek(ifile, 1, SEEK_CUR); |
||
| 326 | |||
| 327 | if (PHYSFS_tell(ifile) != chunk_end) |
||
| 328 | return IFF_CORRUPT; |
||
| 329 | else |
||
| 330 | return IFF_NO_ERROR; |
||
| 331 | } |
||
| 332 | |||
| 333 | // the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data |
||
| 334 | static void skip_chunk(PHYSFS_File *ifile,long len) |
||
| 335 | { |
||
| 336 | int ilen; |
||
| 337 | ilen = (len+1) & ~1; |
||
| 338 | |||
| 339 | PHYSFSX_fseek(ifile,ilen,SEEK_CUR); |
||
| 340 | } |
||
| 341 | |||
| 342 | //read an ILBM or PBM file |
||
| 343 | // Pass pointer to opened file, and to empty bitmap_header structure, and form length |
||
| 344 | static int iff_parse_ilbm_pbm(PHYSFS_File *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm) |
||
| 345 | { |
||
| 346 | int sig,len; |
||
| 347 | long start_pos,end_pos; |
||
| 348 | |||
| 349 | start_pos = PHYSFS_tell(ifile); |
||
| 350 | end_pos = start_pos-4+form_len; |
||
| 351 | |||
| 352 | if (form_type == pbm_sig) |
||
| 353 | bmheader->type = TYPE_PBM; |
||
| 354 | else |
||
| 355 | bmheader->type = TYPE_ILBM; |
||
| 356 | |||
| 357 | while ((PHYSFS_tell(ifile) < end_pos) && (sig=get_sig(ifile)) != EOF) { |
||
| 358 | |||
| 359 | PHYSFS_readSBE32(ifile, &len); |
||
| 360 | |||
| 361 | switch (sig) { |
||
| 362 | |||
| 363 | case bmhd_sig: { |
||
| 364 | int ret; |
||
| 365 | int save_w=bmheader->w,save_h=bmheader->h; |
||
| 366 | |||
| 367 | ret = parse_bmhd(ifile,len,bmheader); |
||
| 368 | |||
| 369 | if (ret != IFF_NO_ERROR) |
||
| 370 | return ret; |
||
| 371 | |||
| 372 | if (bmheader->raw_data) { |
||
| 373 | |||
| 374 | if (save_w != bmheader->w || save_h != bmheader->h) |
||
| 375 | return IFF_BM_MISMATCH; |
||
| 376 | |||
| 377 | } |
||
| 378 | else { |
||
| 379 | MALLOC(bmheader->raw_data, uint8_t[], bmheader->w * bmheader->h); |
||
| 380 | if (!bmheader->raw_data) |
||
| 381 | return IFF_NO_MEM; |
||
| 382 | } |
||
| 383 | |||
| 384 | break; |
||
| 385 | |||
| 386 | } |
||
| 387 | |||
| 388 | case anhd_sig: |
||
| 389 | |||
| 390 | if (!prev_bm) return IFF_CORRUPT; |
||
| 391 | |||
| 392 | bmheader->w = prev_bm->bm_w; |
||
| 393 | bmheader->h = prev_bm->bm_h; |
||
| 394 | bmheader->type = prev_bm->get_type(); |
||
| 395 | |||
| 396 | MALLOC(bmheader->raw_data, uint8_t[], bmheader->w * bmheader->h); |
||
| 397 | |||
| 398 | memcpy(bmheader->raw_data.get(), prev_bm->bm_data, bmheader->w * bmheader->h); |
||
| 399 | skip_chunk(ifile,len); |
||
| 400 | |||
| 401 | break; |
||
| 402 | |||
| 403 | case cmap_sig: |
||
| 404 | { |
||
| 405 | unsigned ncolors=(len/3); |
||
| 406 | |||
| 407 | range_for (auto &p, partial_range(bmheader->palette, ncolors)) |
||
| 408 | { |
||
| 409 | p.r = static_cast<unsigned char>(PHYSFSX_fgetc(ifile)) >> 2; |
||
| 410 | p.g = static_cast<unsigned char>(PHYSFSX_fgetc(ifile)) >> 2; |
||
| 411 | p.b = static_cast<unsigned char>(PHYSFSX_fgetc(ifile)) >> 2; |
||
| 412 | } |
||
| 413 | if (len & 1) PHYSFSX_fgetc(ifile); |
||
| 414 | |||
| 415 | break; |
||
| 416 | } |
||
| 417 | |||
| 418 | case body_sig: |
||
| 419 | { |
||
| 420 | int r; |
||
| 421 | if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR) |
||
| 422 | return r; |
||
| 423 | break; |
||
| 424 | } |
||
| 425 | case dlta_sig: |
||
| 426 | { |
||
| 427 | int r; |
||
| 428 | if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR) |
||
| 429 | return r; |
||
| 430 | break; |
||
| 431 | } |
||
| 432 | default: |
||
| 433 | skip_chunk(ifile,len); |
||
| 434 | break; |
||
| 435 | } |
||
| 436 | } |
||
| 437 | |||
| 438 | if (PHYSFS_tell(ifile) != start_pos-4+form_len) |
||
| 439 | return IFF_CORRUPT; |
||
| 440 | |||
| 441 | return IFF_NO_ERROR; /* ok! */ |
||
| 442 | } |
||
| 443 | |||
| 444 | //convert an ILBM file to a PBM file |
||
| 445 | static int convert_ilbm_to_pbm(iff_bitmap_header *bmheader) |
||
| 446 | { |
||
| 447 | int x,p; |
||
| 448 | int bytes_per_row,byteofs; |
||
| 449 | ubyte checkmask,newbyte,setbit; |
||
| 450 | |||
| 451 | RAIIdmem<uint8_t[]> new_data; |
||
| 452 | MALLOC(new_data, uint8_t[], bmheader->w * bmheader->h); |
||
| 453 | if (new_data == NULL) return IFF_NO_MEM; |
||
| 454 | |||
| 455 | auto destptr = new_data.get(); |
||
| 456 | |||
| 457 | bytes_per_row = 2*((bmheader->w+15)/16); |
||
| 458 | |||
| 459 | for (int y=0;y<bmheader->h;y++) { |
||
| 460 | |||
| 461 | const auto rowptr = reinterpret_cast<int8_t *>(&bmheader->raw_data[y * bytes_per_row * bmheader->nplanes]); |
||
| 462 | |||
| 463 | for (x=0,checkmask=0x80;x<bmheader->w;x++) { |
||
| 464 | |||
| 465 | byteofs = x >> 3; |
||
| 466 | |||
| 467 | for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) { |
||
| 468 | |||
| 469 | if (rowptr[bytes_per_row * p + byteofs] & checkmask) |
||
| 470 | newbyte |= setbit; |
||
| 471 | |||
| 472 | setbit <<= 1; |
||
| 473 | } |
||
| 474 | |||
| 475 | *destptr++ = newbyte; |
||
| 476 | |||
| 477 | if ((checkmask >>= 1) == 0) checkmask=0x80; |
||
| 478 | } |
||
| 479 | |||
| 480 | } |
||
| 481 | |||
| 482 | bmheader->raw_data = std::move(new_data); |
||
| 483 | |||
| 484 | bmheader->type = TYPE_PBM; |
||
| 485 | |||
| 486 | return IFF_NO_ERROR; |
||
| 487 | } |
||
| 488 | |||
| 489 | #define INDEX_TO_15BPP(i) (static_cast<short>((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31))) |
||
| 490 | |||
| 491 | namespace dsx { |
||
| 492 | static int convert_rgb15(grs_bitmap &bm,iff_bitmap_header &bmheader) |
||
| 493 | { |
||
| 494 | palette_array_t::iterator palptr = begin(bmheader.palette); |
||
| 495 | |||
| 496 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 497 | for (int y=0; y < bm.bm_h; y++) { |
||
| 498 | for (int x=0; x < bmheader.w; x++) |
||
| 499 | gr_bm_pixel(*grd_curcanv, bm, x, y, INDEX_TO_15BPP(bm.get_bitmap_data()[y * bmheader.w + x])); |
||
| 500 | } |
||
| 501 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 502 | uint16_t *new_data; |
||
| 503 | MALLOC(new_data, ushort, bm.bm_w * bm.bm_h * 2); |
||
| 504 | if (new_data == NULL) |
||
| 505 | return IFF_NO_MEM; |
||
| 506 | |||
| 507 | unsigned newptr = 0; |
||
| 508 | for (int y=0; y < bm.bm_h; y++) { |
||
| 509 | |||
| 510 | for (int x=0; x < bmheader.w; x++) |
||
| 511 | new_data[newptr++] = INDEX_TO_15BPP(bm.get_bitmap_data()[y * bmheader.w + x]); |
||
| 512 | |||
| 513 | } |
||
| 514 | |||
| 515 | d_free(bm.bm_mdata); //get rid of old-style data |
||
| 516 | bm.bm_mdata = reinterpret_cast<uint8_t *>(new_data); //..and point to new data |
||
| 517 | |||
| 518 | bm.bm_rowsize *= 2; //two bytes per row |
||
| 519 | #endif |
||
| 520 | return IFF_NO_ERROR; |
||
| 521 | |||
| 522 | } |
||
| 523 | } |
||
| 524 | |||
| 525 | //copy an iff header structure to a grs_bitmap structure |
||
| 526 | static void copy_iff_to_grs(grs_bitmap &bm,iff_bitmap_header &bmheader) |
||
| 527 | { |
||
| 528 | gr_init_bitmap(bm, static_cast<bm_mode>(bmheader.type), 0, 0, bmheader.w, bmheader.h, bmheader.w, bmheader.raw_data.release()); |
||
| 529 | } |
||
| 530 | |||
| 531 | //if bm->bm_data is set, use it (making sure w & h are correct), else |
||
| 532 | //allocate the memory |
||
| 533 | static int iff_parse_bitmap(PHYSFS_File *ifile, grs_bitmap &bm, int bitmap_type, palette_array_t *palette, grs_bitmap *prev_bm) |
||
| 534 | { |
||
| 535 | int ret; //return code |
||
| 536 | iff_bitmap_header bmheader; |
||
| 537 | int sig,form_len; |
||
| 538 | long form_type; |
||
| 539 | |||
| 540 | bmheader.raw_data.reset(bm.get_bitmap_data()); |
||
| 541 | |||
| 542 | if (bmheader.raw_data) { |
||
| 543 | bmheader.w = bm.bm_w; |
||
| 544 | bmheader.h = bm.bm_h; |
||
| 545 | }//added 05/17/99 Matt Mueller - don't just leave them unitialized |
||
| 546 | else{ |
||
| 547 | bmheader.w=bmheader.h=0; |
||
| 548 | } |
||
| 549 | |||
| 550 | sig=get_sig(ifile); |
||
| 551 | |||
| 552 | if (sig != form_sig) { |
||
| 553 | return IFF_NOT_IFF; |
||
| 554 | } |
||
| 555 | |||
| 556 | PHYSFS_readSBE32(ifile, &form_len); |
||
| 557 | |||
| 558 | form_type = get_sig(ifile); |
||
| 559 | |||
| 560 | if (form_type == anim_sig) |
||
| 561 | ret = IFF_FORM_ANIM; |
||
| 562 | else if ((form_type == pbm_sig) || (form_type == ilbm_sig)) |
||
| 563 | ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm); |
||
| 564 | else |
||
| 565 | ret = IFF_UNKNOWN_FORM; |
||
| 566 | |||
| 567 | if (ret != IFF_NO_ERROR) { //got an error parsing |
||
| 568 | return ret; |
||
| 569 | } |
||
| 570 | |||
| 571 | //If IFF file is ILBM, convert to PPB |
||
| 572 | if (bmheader.type == TYPE_ILBM) { |
||
| 573 | |||
| 574 | ret = convert_ilbm_to_pbm(&bmheader); |
||
| 575 | |||
| 576 | if (ret != IFF_NO_ERROR) |
||
| 577 | return ret; |
||
| 578 | } |
||
| 579 | |||
| 580 | //Copy data from iff_bitmap_header structure into grs_bitmap structure |
||
| 581 | |||
| 582 | copy_iff_to_grs(bm,bmheader); |
||
| 583 | |||
| 584 | if (palette) |
||
| 585 | *palette = bmheader.palette; |
||
| 586 | |||
| 587 | //Now do post-process if required |
||
| 588 | |||
| 589 | if (bitmap_type == bm_mode::rgb15) { |
||
| 590 | ret = convert_rgb15(bm, bmheader); |
||
| 591 | if (ret != IFF_NO_ERROR) |
||
| 592 | return ret; |
||
| 593 | } |
||
| 594 | |||
| 595 | return ret; |
||
| 596 | |||
| 597 | } |
||
| 598 | |||
| 599 | //returns error codes - see IFF.H. see GR.H for bitmap_type |
||
| 600 | int iff_read_bitmap(const char *const ifilename, grs_bitmap &bm, palette_array_t *const palette) |
||
| 601 | { |
||
| 602 | int ret; //return code |
||
| 603 | auto ifile = PHYSFSX_openReadBuffered(ifilename); |
||
| 604 | if (!ifile) |
||
| 605 | return IFF_NO_FILE; |
||
| 606 | |||
| 607 | bm.bm_data = nullptr; |
||
| 608 | ret = iff_parse_bitmap(ifile, bm, bm_mode::linear, palette, nullptr); |
||
| 609 | return ret; |
||
| 610 | } |
||
| 611 | |||
| 612 | #define BMHD_SIZE 20 |
||
| 613 | |||
| 614 | #if 0 |
||
| 615 | static int write_bmhd(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header) |
||
| 616 | { |
||
| 617 | put_sig(bmhd_sig,ofile); |
||
| 618 | PHYSFS_writeSBE32(ofile, BMHD_SIZE); |
||
| 619 | |||
| 620 | PHYSFS_writeSBE16(ofile, bitmap_header->w); |
||
| 621 | PHYSFS_writeSBE16(ofile, bitmap_header->h); |
||
| 622 | PHYSFS_writeSBE16(ofile, bitmap_header->x); |
||
| 623 | PHYSFS_writeSBE16(ofile, bitmap_header->y); |
||
| 624 | |||
| 625 | PHYSFSX_writeU8(ofile, bitmap_header->nplanes); |
||
| 626 | PHYSFSX_writeU8(ofile, bitmap_header->masking); |
||
| 627 | PHYSFSX_writeU8(ofile, bitmap_header->compression); |
||
| 628 | PHYSFSX_writeU8(ofile, 0); /* pad */ |
||
| 629 | |||
| 630 | PHYSFS_writeSBE16(ofile, bitmap_header->transparentcolor); |
||
| 631 | PHYSFSX_writeU8(ofile, bitmap_header->xaspect); |
||
| 632 | PHYSFSX_writeU8(ofile, bitmap_header->yaspect); |
||
| 633 | |||
| 634 | PHYSFS_writeSBE16(ofile, bitmap_header->pagewidth); |
||
| 635 | PHYSFS_writeSBE16(ofile, bitmap_header->pageheight); |
||
| 636 | |||
| 637 | return IFF_NO_ERROR; |
||
| 638 | |||
| 639 | } |
||
| 640 | |||
| 641 | static int write_pal(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header) |
||
| 642 | { |
||
| 643 | int n_colors = 1<<bitmap_header->nplanes; |
||
| 644 | |||
| 645 | put_sig(cmap_sig,ofile); |
||
| 646 | // PHYSFS_writeSBE32(sizeof(pal_entry) * n_colors,ofile); |
||
| 647 | PHYSFS_writeSBE32(ofile, 3 * n_colors); |
||
| 648 | |||
| 649 | range_for (auto &c, bitmap_header->palette) |
||
| 650 | { |
||
| 651 | unsigned char r,g,b; |
||
| 652 | r = c.r * 4 + (c.r?3:0); |
||
| 653 | g = c.g * 4 + (c.g?3:0); |
||
| 654 | b = c.b * 4 + (c.b?3:0); |
||
| 655 | PHYSFSX_writeU8(ofile, r); |
||
| 656 | PHYSFSX_writeU8(ofile, g); |
||
| 657 | PHYSFSX_writeU8(ofile, b); |
||
| 658 | } |
||
| 659 | |||
| 660 | return IFF_NO_ERROR; |
||
| 661 | } |
||
| 662 | |||
| 663 | static int rle_span(ubyte *dest,ubyte *src,int len) |
||
| 664 | { |
||
| 665 | int lit_cnt,rep_cnt; |
||
| 666 | ubyte last,*cnt_ptr,*dptr; |
||
| 667 | |||
| 668 | cnt_ptr=0; |
||
| 669 | |||
| 670 | dptr = dest; |
||
| 671 | |||
| 672 | last=src[0]; lit_cnt=1; |
||
| 673 | |||
| 674 | for (int n=1;n<len;n++) { |
||
| 675 | |||
| 676 | if (src[n] == last) { |
||
| 677 | |||
| 678 | rep_cnt = 2; |
||
| 679 | |||
| 680 | n++; |
||
| 681 | while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;} |
||
| 682 | |||
| 683 | if (rep_cnt > 2 || lit_cnt < 2) { |
||
| 684 | |||
| 685 | if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;} //save old lit count |
||
| 686 | *dptr++ = -(rep_cnt-1); |
||
| 687 | *dptr++ = last; |
||
| 688 | last = src[n]; |
||
| 689 | lit_cnt = (n<len)?1:0; |
||
| 690 | |||
| 691 | continue; //go to next char |
||
| 692 | } else n--; |
||
| 693 | |||
| 694 | } |
||
| 695 | |||
| 696 | { |
||
| 697 | |||
| 698 | if (lit_cnt==1) { |
||
| 699 | cnt_ptr = dptr++; //save place for count |
||
| 700 | *dptr++=last; //store first char |
||
| 701 | } |
||
| 702 | |||
| 703 | *dptr++ = last = src[n]; |
||
| 704 | |||
| 705 | if (lit_cnt == 127) { |
||
| 706 | *cnt_ptr = lit_cnt; |
||
| 707 | //cnt_ptr = dptr++; |
||
| 708 | lit_cnt = 1; |
||
| 709 | last = src[++n]; |
||
| 710 | } |
||
| 711 | else lit_cnt++; |
||
| 712 | } |
||
| 713 | |||
| 714 | |||
| 715 | } |
||
| 716 | |||
| 717 | if (lit_cnt==1) { |
||
| 718 | *dptr++ = 0; |
||
| 719 | *dptr++=last; //store first char |
||
| 720 | } |
||
| 721 | else if (lit_cnt > 1) |
||
| 722 | *cnt_ptr = lit_cnt-1; |
||
| 723 | |||
| 724 | return dptr-dest; |
||
| 725 | } |
||
| 726 | |||
| 727 | #define EVEN(a) ((a+1)&0xfffffffel) |
||
| 728 | |||
| 729 | //returns length of chunk |
||
| 730 | static int write_body(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header,int compression_on) |
||
| 731 | { |
||
| 732 | int w=bitmap_header->w,h=bitmap_header->h; |
||
| 733 | int y,odd=w&1; |
||
| 734 | long len = EVEN(w) * h,newlen,total_len=0; |
||
| 735 | uint8_t *p=bitmap_header->raw_data; |
||
| 736 | long save_pos; |
||
| 737 | |||
| 738 | put_sig(body_sig,ofile); |
||
| 739 | save_pos = PHYSFS_tell(ofile); |
||
| 740 | PHYSFS_writeSBE32(ofile, len); |
||
| 741 | |||
| 742 | RAIIdmem<uint8_t[]> new_span; |
||
| 743 | MALLOC( new_span, uint8_t[], bitmap_header->w + (bitmap_header->w/128+2)*2); |
||
| 744 | if (!new_span) return IFF_NO_MEM; |
||
| 745 | |||
| 746 | for (y=bitmap_header->h;y--;) { |
||
| 747 | |||
| 748 | if (compression_on) { |
||
| 749 | total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd); |
||
| 750 | PHYSFS_write(ofile,new_span,newlen,1); |
||
| 751 | } |
||
| 752 | else |
||
| 753 | PHYSFS_write(ofile,p,bitmap_header->w+odd,1); |
||
| 754 | |||
| 755 | p+=bitmap_header->row_size; //bitmap_header->w; |
||
| 756 | } |
||
| 757 | |||
| 758 | if (compression_on) { //write actual data length |
||
| 759 | Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0); |
||
| 760 | (void)save_pos; |
||
| 761 | PHYSFS_writeSBE32(ofile, total_len); |
||
| 762 | Assert(PHYSFSX_fseek(ofile,total_len,SEEK_CUR)==0); |
||
| 763 | if (total_len&1) PHYSFSX_writeU8(ofile, 0); //pad to even |
||
| 764 | } |
||
| 765 | return ((compression_on) ? (EVEN(total_len)+8) : (len+8)); |
||
| 766 | |||
| 767 | } |
||
| 768 | |||
| 769 | #if WRITE_TINY |
||
| 770 | //write a small representation of a bitmap. returns size |
||
| 771 | int write_tiny(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header,int compression_on) |
||
| 772 | { |
||
| 773 | int skip; |
||
| 774 | int new_w,new_h; |
||
| 775 | int len,total_len=0,newlen; |
||
| 776 | int x,xofs,odd; |
||
| 777 | uint8_t *p = bitmap_header->raw_data; |
||
| 778 | ubyte tspan[80],new_span[80*2]; |
||
| 779 | long save_pos; |
||
| 780 | |||
| 781 | skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64); |
||
| 782 | |||
| 783 | new_w = bitmap_header->w / skip; |
||
| 784 | new_h = bitmap_header->h / skip; |
||
| 785 | |||
| 786 | odd = new_w & 1; |
||
| 787 | |||
| 788 | len = new_w * new_h + 4; |
||
| 789 | |||
| 790 | put_sig(tiny_sig,ofile); |
||
| 791 | save_pos = PHYSFS_tell(ofile); |
||
| 792 | PHYSFS_writeSBE32(ofile, EVEN(len)); |
||
| 793 | |||
| 794 | PHYSFS_writeSBE16(ofile, new_w); |
||
| 795 | PHYSFS_writeSBE16(ofile, new_h); |
||
| 796 | |||
| 797 | for (int y=0;y<new_h;y++) { |
||
| 798 | for (x=xofs=0;x<new_w;x++,xofs+=skip) |
||
| 799 | tspan[x] = p[xofs]; |
||
| 800 | |||
| 801 | if (compression_on) { |
||
| 802 | total_len += newlen = rle_span(new_span,tspan,new_w+odd); |
||
| 803 | PHYSFS_write(ofile,new_span,newlen,1); |
||
| 804 | } |
||
| 805 | else |
||
| 806 | PHYSFS_write(ofile,p,new_w+odd,1); |
||
| 807 | |||
| 808 | p += skip * bitmap_header->row_size; //bitmap_header->w; |
||
| 809 | |||
| 810 | } |
||
| 811 | |||
| 812 | if (compression_on) { |
||
| 813 | Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0); |
||
| 814 | (void)save_pos; |
||
| 815 | PHYSFS_writeSBE32(ofile, 4+total_len); |
||
| 816 | Assert(PHYSFSX_fseek(ofile,4+total_len,SEEK_CUR)==0); |
||
| 817 | if (total_len&1) PHYSFSX_writeU8(ofile, 0); //pad to even |
||
| 818 | } |
||
| 819 | |||
| 820 | return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8)); |
||
| 821 | } |
||
| 822 | #endif |
||
| 823 | |||
| 824 | static int write_pbm(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header,int compression_on) /* writes a pbm iff file */ |
||
| 825 | { |
||
| 826 | int ret; |
||
| 827 | long raw_size = EVEN(bitmap_header->w) * bitmap_header->h; |
||
| 828 | long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(rgb_t)*(1<<bitmap_header->nplanes)+8; |
||
| 829 | long save_pos; |
||
| 830 | |||
| 831 | put_sig(form_sig,ofile); |
||
| 832 | save_pos = PHYSFS_tell(ofile); |
||
| 833 | PHYSFS_writeSBE32(ofile, pbm_size+8); |
||
| 834 | put_sig(pbm_sig,ofile); |
||
| 835 | |||
| 836 | ret = write_bmhd(ofile,bitmap_header); |
||
| 837 | if (ret != IFF_NO_ERROR) return ret; |
||
| 838 | |||
| 839 | ret = write_pal(ofile,bitmap_header); |
||
| 840 | if (ret != IFF_NO_ERROR) return ret; |
||
| 841 | |||
| 842 | #if WRITE_TINY |
||
| 843 | tiny_size = write_tiny(ofile,bitmap_header,compression_on); |
||
| 844 | #else |
||
| 845 | tiny_size = 0; |
||
| 846 | #endif |
||
| 847 | |||
| 848 | body_size = write_body(ofile,bitmap_header,compression_on); |
||
| 849 | |||
| 850 | pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(rgb_t)*(1<<bitmap_header->nplanes)+8; |
||
| 851 | |||
| 852 | Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0); |
||
| 853 | (void)save_pos; |
||
| 854 | PHYSFS_writeSBE32(ofile, pbm_size+8); |
||
| 855 | Assert(PHYSFSX_fseek(ofile,pbm_size+8,SEEK_CUR)==0); |
||
| 856 | |||
| 857 | return ret; |
||
| 858 | |||
| 859 | } |
||
| 860 | |||
| 861 | //writes an IFF file from a grs_bitmap structure. writes palette if not null |
||
| 862 | //returns error codes - see IFF.H. |
||
| 863 | int iff_write_bitmap(const char *ofilename,grs_bitmap *bm,palette_array_t *palette) |
||
| 864 | { |
||
| 865 | iff_bitmap_header bmheader; |
||
| 866 | int ret; |
||
| 867 | int compression_on; |
||
| 868 | |||
| 869 | if (bm->bm_type == bm_mode::rgb15) return IFF_BAD_BM_TYPE; |
||
| 870 | |||
| 871 | #if COMPRESS |
||
| 872 | compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH); |
||
| 873 | #else |
||
| 874 | compression_on = 0; |
||
| 875 | #endif |
||
| 876 | |||
| 877 | //fill in values in bmheader |
||
| 878 | |||
| 879 | bmheader.x = bmheader.y = 0; |
||
| 880 | bmheader.w = bm->bm_w; |
||
| 881 | bmheader.h = bm->bm_h; |
||
| 882 | bmheader.type = TYPE_PBM; |
||
| 883 | bmheader.transparentcolor = iff_transparent_color; |
||
| 884 | bmheader.pagewidth = bm->bm_w; //I don't think it matters what I write |
||
| 885 | bmheader.pageheight = bm->bm_h; |
||
| 886 | bmheader.nplanes = 8; |
||
| 887 | bmheader.masking = mskNone; |
||
| 888 | if (iff_has_transparency) { |
||
| 889 | bmheader.masking |= mskHasTransparentColor; |
||
| 890 | } |
||
| 891 | bmheader.compression = (compression_on?cmpByteRun1:cmpNone); |
||
| 892 | |||
| 893 | bmheader.xaspect = bmheader.yaspect = 1; //I don't think it matters what I write |
||
| 894 | bmheader.raw_data = bm->get_bitmap_data(); |
||
| 895 | bmheader.row_size = bm->bm_rowsize; |
||
| 896 | |||
| 897 | if (palette) |
||
| 898 | bmheader.palette = *palette; |
||
| 899 | |||
| 900 | //open file and write |
||
| 901 | |||
| 902 | RAIIPHYSFS_File ofile{PHYSFS_openWrite(ofilename)}; |
||
| 903 | if (!ofile) |
||
| 904 | return IFF_NO_FILE; |
||
| 905 | |||
| 906 | ret = write_pbm(ofile,&bmheader,compression_on); |
||
| 907 | return ret; |
||
| 908 | } |
||
| 909 | #endif |
||
| 910 | |||
| 911 | //read in many brushes. fills in array of pointers, and n_bitmaps. |
||
| 912 | //returns iff error codes |
||
| 913 | int iff_read_animbrush(const char *ifilename,std::array<std::unique_ptr<grs_main_bitmap>, MAX_BITMAPS_PER_BRUSH> &bm_list,unsigned *n_bitmaps,palette_array_t &palette) |
||
| 914 | { |
||
| 915 | int ret = IFF_NO_ERROR; //return code |
||
| 916 | int sig,form_len; |
||
| 917 | long form_type; |
||
| 918 | |||
| 919 | *n_bitmaps=0; |
||
| 920 | |||
| 921 | auto ifile = PHYSFSX_openReadBuffered(ifilename); |
||
| 922 | if (!ifile) |
||
| 923 | return IFF_NO_FILE; |
||
| 924 | |||
| 925 | sig=get_sig(ifile); |
||
| 926 | PHYSFS_readSBE32(ifile, &form_len); |
||
| 927 | |||
| 928 | if (sig != form_sig) { |
||
| 929 | ret = IFF_NOT_IFF; |
||
| 930 | goto done; |
||
| 931 | } |
||
| 932 | |||
| 933 | form_type = get_sig(ifile); |
||
| 934 | |||
| 935 | if ((form_type == pbm_sig) || (form_type == ilbm_sig)) |
||
| 936 | ret = IFF_FORM_BITMAP; |
||
| 937 | else if (form_type == anim_sig) { |
||
| 938 | int anim_end = PHYSFS_tell(ifile) + form_len - 4; |
||
| 939 | |||
| 940 | while (PHYSFS_tell(ifile) < anim_end && *n_bitmaps < bm_list.size()) { |
||
| 941 | |||
| 942 | grs_bitmap *prev_bm; |
||
| 943 | |||
| 944 | prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1].get() : nullptr; |
||
| 945 | |||
| 946 | auto &n = bm_list[*n_bitmaps]; |
||
| 947 | n = std::make_unique<grs_main_bitmap>(); |
||
| 948 | |||
| 949 | ret = iff_parse_bitmap(ifile, *n.get(), form_type, *n_bitmaps > 0 ? nullptr : &palette, prev_bm); |
||
| 950 | |||
| 951 | if (ret != IFF_NO_ERROR) |
||
| 952 | goto done; |
||
| 953 | |||
| 954 | (*n_bitmaps)++; |
||
| 955 | } |
||
| 956 | |||
| 957 | if (PHYSFS_tell(ifile) < anim_end) //ran out of room |
||
| 958 | ret = IFF_TOO_MANY_BMS; |
||
| 959 | |||
| 960 | } |
||
| 961 | else |
||
| 962 | ret = IFF_UNKNOWN_FORM; |
||
| 963 | |||
| 964 | done: |
||
| 965 | return ret; |
||
| 966 | } |
||
| 967 | |||
| 968 | //text for error messges |
||
| 969 | constexpr char error_messages[] = { |
||
| 970 | "No error.\0" |
||
| 971 | "Not enough mem for loading or processing bitmap.\0" |
||
| 972 | "IFF file has unknown FORM type.\0" |
||
| 973 | "Not an IFF file.\0" |
||
| 974 | "Cannot open file.\0" |
||
| 975 | "Tried to save invalid type, like bm_mode::rgb15.\0" |
||
| 976 | "Bad data in file.\0" |
||
| 977 | "ANIM file cannot be loaded with normal bitmap loader.\0" |
||
| 978 | "Normal bitmap file cannot be loaded with anim loader.\0" |
||
| 979 | "Array not big enough on anim brush read.\0" |
||
| 980 | "Unknown mask type in bitmap header.\0" |
||
| 981 | "Error reading file.\0" |
||
| 982 | }; |
||
| 983 | |||
| 984 | |||
| 985 | //function to return pointer to error message |
||
| 986 | const char *iff_errormsg(int error_number) |
||
| 987 | { |
||
| 988 | const char *p = error_messages; |
||
| 989 | |||
| 990 | while (error_number--) { |
||
| 991 | |||
| 992 | if (!p) return NULL; |
||
| 993 | |||
| 994 | p += strlen(p)+1; |
||
| 995 | |||
| 996 | } |
||
| 997 | |||
| 998 | return p; |
||
| 999 | |||
| 1000 | } |
||
| 1001 | |||
| 1002 |