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