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.
15 static char rcsid[] = "$Id: iff.c,v 1.1.1.1 2001-01-19 03:29:58 bradleyb Exp $";
20 #define COMPRESS 1 //do the RLE or not? (for debugging mostly)
21 #define WRITE_TINY 0 //should we write a TINY chunk?
23 #define MIN_COMPRESS_WIDTH 65 //don't compress if less than this wide
32 //#include "nocfile.h"
36 //Internal constants and structures for this library
38 //Type values for bitmaps
49 #define mskHasTransparentColor 2
51 //Palette entry structure
52 typedef struct pal_entry {byte r,g,b;} pal_entry;
54 //structure of the header in the file
55 typedef struct iff_bitmap_header {
56 short w,h; //width and height of this bitmap
57 short x,y; //generally unused
58 short type; //see types above
59 short transparentcolor; //which color is transparent (if any)
60 short pagewidth,pageheight; //width & height of source screen
61 byte nplanes; //number of planes (8 for 256 color image)
62 byte masking,compression; //see constants above
63 byte xaspect,yaspect; //aspect ratio (usually 5/6)
64 pal_entry palette[256]; //the palette for this bitmap
65 ubyte *raw_data; //ptr to array of data
66 short row_size; //offset to next row
69 ubyte iff_transparent_color;
70 ubyte iff_has_transparency; // 0=no transparency, 1=iff_transparent_color is valid
72 typedef struct fake_file {
78 #define MIN(a,b) ((a<b)?a:b)
80 #define MAKE_SIG(a,b,c,d) (((long)(a)<<24)+((long)(b)<<16)+((c)<<8)+(d))
82 #define form_sig MAKE_SIG('F','O','R','M')
83 #define ilbm_sig MAKE_SIG('I','L','B','M')
84 #define body_sig MAKE_SIG('B','O','D','Y')
85 #define pbm_sig MAKE_SIG('P','B','M',' ')
86 #define bmhd_sig MAKE_SIG('B','M','H','D')
87 #define anhd_sig MAKE_SIG('A','N','H','D')
88 #define cmap_sig MAKE_SIG('C','M','A','P')
89 #define tiny_sig MAKE_SIG('T','I','N','Y')
90 #define anim_sig MAKE_SIG('A','N','I','M')
91 #define dlta_sig MAKE_SIG('D','L','T','A')
94 //void printsig(long s)
96 // char *t=(char *) &s;
98 ///* printf("%c%c%c%c",*(&s+3),*(&s+2),*(&s+1),s);*/
99 // printf("%c%c%c%c",t[3],t[2],t[1],t[0]);
103 long get_sig(FFILE *f)
107 // if ((s[3]=cfgetc(f))==EOF) return(EOF);
108 // if ((s[2]=cfgetc(f))==EOF) return(EOF);
109 // if ((s[1]=cfgetc(f))==EOF) return(EOF);
110 // if ((s[0]=cfgetc(f))==EOF) return(EOF);
113 if (f->position>=f->length) return EOF;
114 s[3] = f->data[f->position++];
115 if (f->position>=f->length) return EOF;
116 s[2] = f->data[f->position++];
117 if (f->position>=f->length) return EOF;
118 s[1] = f->data[f->position++];
119 if (f->position>=f->length) return EOF;
120 s[0] = f->data[f->position++];
122 if (f->position>=f->length) return EOF;
123 s[0] = f->data[f->position++];
124 if (f->position>=f->length) return EOF;
125 s[1] = f->data[f->position++];
126 if (f->position>=f->length) return EOF;
127 s[2] = f->data[f->position++];
128 if (f->position>=f->length) return EOF;
129 s[3] = f->data[f->position++];
132 return(*((long *) s));
135 int put_sig(long sig,FILE *f)
137 char *s = (char *) &sig;
142 return fputc(s[0],f);
146 char get_byte(FFILE *f)
149 return f->data[f->position++];
152 int put_byte(unsigned char c,FILE *f)
159 int get_word(FFILE *f)
166 if (f->position>=f->length) return EOF;
167 c1 = f->data[f->position++];
168 if (f->position>=f->length) return EOF;
169 c0 = f->data[f->position++];
171 if (c0==0xff) return(EOF);
173 return(((int)c1<<8) + c0);
177 int put_word(int n,FILE *f)
181 c0 = (n & 0xff00) >> 8;
185 return put_byte(c1,f);
188 int put_long(long n,FILE *f)
192 n0 = (int) ((n & 0xffff0000l) >> 16);
193 n1 = (int) (n & 0xffff);
196 return put_word(n1,f);
200 long get_long(FFILE *f)
202 unsigned char c0,c1,c2,c3;
209 if (f->position>=f->length) return EOF;
210 c3 = f->data[f->position++];
211 if (f->position>=f->length) return EOF;
212 c2 = f->data[f->position++];
213 if (f->position>=f->length) return EOF;
214 c1 = f->data[f->position++];
215 if (f->position>=f->length) return EOF;
216 c0 = f->data[f->position++];
218 //printf("get_long %x %x %x %x\n",c3,c2,c1,c0);
220 // if (c0==0xff) return(EOF);
222 return(((long)c3<<24) + ((long)c2<<16) + ((long)c1<<8) + c0);
226 int parse_bmhd(FFILE *ifile,long len,iff_bitmap_header *bmheader)
228 len++; /* so no "parm not used" warning */
230 // debug("parsing bmhd len=%ld\n",len);
232 bmheader->w = get_word(ifile);
233 bmheader->h = get_word(ifile);
234 bmheader->x = get_word(ifile);
235 bmheader->y = get_word(ifile);
237 bmheader->nplanes = get_byte(ifile);
238 bmheader->masking = get_byte(ifile);
239 bmheader->compression = get_byte(ifile);
240 get_byte(ifile); /* skip pad */
242 bmheader->transparentcolor = get_word(ifile);
243 bmheader->xaspect = get_byte(ifile);
244 bmheader->yaspect = get_byte(ifile);
246 bmheader->pagewidth = get_word(ifile);
247 bmheader->pageheight = get_word(ifile);
249 iff_transparent_color = bmheader->transparentcolor;
251 iff_has_transparency = 0;
253 if (bmheader->masking == mskHasTransparentColor)
254 iff_has_transparency = 1;
256 else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask)
257 return IFF_UNKNOWN_MASK;
259 // debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y);
260 // debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor);
266 // the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data
267 int parse_body(FFILE *ifile,long len,iff_bitmap_header *bmheader)
269 unsigned char *p=bmheader->raw_data;
272 int nn,wid_cnt,end_cnt,plane;
274 unsigned char *data_end;
278 end_pos = ifile->position + len;
282 if (bmheader->type == TYPE_PBM) {
285 } else if (bmheader->type == TYPE_ILBM) {
286 width = (bmheader->w+7)/8;
287 depth=bmheader->nplanes;
290 end_cnt = (width&1)?-1:0;
292 data_end = p + width*bmheader->h*depth;
294 if (bmheader->compression == cmpNone) { /* no compression */
297 for (y=bmheader->h;y;y--) {
299 // for (x=bmheader->w;x;x--) *p++=cfgetc(ifile);
300 // cfread(p, bmheader->w, 1, ifile);
303 for (x=0;x<width*depth;x++)
304 *p++=ifile->data[ifile->position++];
306 if (bmheader->masking == mskHasMask)
307 ifile->position += width; //skip mask!
309 // if (bmheader->w & 1) ignore = cfgetc(ifile);
310 if (bmheader->w & 1) ifile->position++;
313 //cnt = len - bmheader->h * ((bmheader->w+1)&~1);
316 else if (bmheader->compression == cmpByteRun1)
317 for (wid_cnt=width,plane=0;ifile->position<end_pos && p<data_end;) {
320 // if (old_cnt-cnt > 2048) {
325 if (wid_cnt == end_cnt) {
328 if ((bmheader->masking == mskHasMask && plane==depth+1) ||
329 (bmheader->masking != mskHasMask && plane==depth))
333 Assert(wid_cnt > end_cnt);
336 n=ifile->data[ifile->position++];
338 if (n >= 0) { // copy next n+1 bytes from source, they are not compressed
341 if (wid_cnt==-1) {--nn; Assert(width&1);}
342 if (plane==depth) //masking row
343 ifile->position += nn;
345 while (nn--) *p++=ifile->data[ifile->position++];
346 if (wid_cnt==-1) ifile->position++;
348 else if (n>=-127) { // next -n + 1 bytes are following byte
349 c=ifile->data[ifile->position++];
352 if (wid_cnt==-1) {--nn; Assert(width&1);}
353 if (plane!=depth) //not masking row
354 {memset(p,c,nn); p+=nn;}
358 if ((p-bmheader->raw_data) % width == 0)
361 Assert((p-bmheader->raw_data) - (width*row_count) < width);
366 if (p!=data_end) //if we don't have the whole bitmap...
367 return IFF_CORRUPT; //...the give an error
369 //Pretend we read the whole chuck, because if we didn't, it's because
370 //we didn't read the last mask like or the last rle record for padding
371 //or whatever and it's not important, because we check to make sure
372 //we got the while bitmap, and that's what really counts.
374 ifile->position = end_pos;
376 if (ignore) ignore++; // haha, suppress the evil warning message
381 //modify passed bitmap
382 int parse_delta(FFILE *ifile,long len,iff_bitmap_header *bmheader)
384 unsigned char *p=bmheader->raw_data;
386 long chunk_end = ifile->position + len;
388 get_long(ifile); //longword, seems to be equal to 4. Don't know what it is
390 for (y=0;y<bmheader->h;y++) {
392 int cnt = bmheader->w;
395 n_items = get_byte(ifile);
399 code = get_byte(ifile);
401 if (code==0) { //repeat
404 rep = get_byte(ifile);
405 val = get_byte(ifile);
413 else if (code > 0x80) { //skip
425 *p++ = get_byte(ifile);
441 if (ifile->position == chunk_end-1) //pad
444 if (ifile->position != chunk_end)
450 // the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
451 void skip_chunk(FFILE *ifile,long len)
457 //printf( "Skipping %d chunk\n", ilen );
459 ifile->position += ilen;
461 if (ifile->position >= ifile->length ) {
462 ifile->position = ifile->length;
466 // for (i=0; i<ilen; i++ )
467 // c = cfgetc(ifile);
468 //Assert(cfseek(ifile,ilen,SEEK_CUR)==0);
471 //read an ILBM or PBM file
472 // Pass pointer to opened file, and to empty bitmap_header structure, and form length
473 int iff_parse_ilbm_pbm(FFILE *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm)
477 long start_pos,end_pos;
479 start_pos = ifile->position;
480 end_pos = start_pos-4+form_len;
482 // printf(" %ld ",form_len);
483 // printsig(form_type);
486 if (form_type == pbm_sig)
487 bmheader->type = TYPE_PBM;
489 bmheader->type = TYPE_ILBM;
491 while ((ifile->position < end_pos) && (sig=get_sig(ifile)) != EOF) {
498 // printf(" %ld\n",len);
504 int save_w=bmheader->w,save_h=bmheader->h;
506 //printf("Parsing header\n");
508 ret = parse_bmhd(ifile,len,bmheader);
510 if (ret != IFF_NO_ERROR)
513 if (bmheader->raw_data) {
515 if (save_w != bmheader->w || save_h != bmheader->h)
516 return IFF_BM_MISMATCH;
521 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
522 if (!bmheader->raw_data)
532 if (!prev_bm) return IFF_CORRUPT;
534 bmheader->w = prev_bm->bm_w;
535 bmheader->h = prev_bm->bm_h;
536 bmheader->type = prev_bm->bm_type;
538 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
540 memcpy(bmheader->raw_data, prev_bm->bm_data, bmheader->w * bmheader->h );
541 skip_chunk(ifile,len);
547 int ncolors=(int) (len/3),cnum;
550 //printf("Parsing RGB map\n");
551 for (cnum=0;cnum<ncolors;cnum++) {
555 r = ifile->data[ifile->position++];
556 g = ifile->data[ifile->position++];
557 b = ifile->data[ifile->position++];
558 r >>= 2; bmheader->palette[cnum].r = r;
559 g >>= 2; bmheader->palette[cnum].g = g;
560 b >>= 2; bmheader->palette[cnum].b = b;
562 //if (len & 1) ignore = cfgetc(ifile);
563 if (len & 1 ) ifile->position++;
571 //printf("Parsing body\n");
572 if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR)
579 if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR)
584 skip_chunk(ifile,len);
589 //if (ignore) ignore++;
591 if (ifile->position != start_pos-4+form_len)
594 return IFF_NO_ERROR; /* ok! */
597 //convert an ILBM file to a PBM file
598 int convert_ilbm_to_pbm(iff_bitmap_header *bmheader)
601 byte *new_data,*destptr,*rowptr;
602 int bytes_per_row,byteofs;
603 ubyte checkmask,newbyte,setbit;
605 MALLOC( new_data, byte, bmheader->w * bmheader->h );
606 if (new_data == NULL) return IFF_NO_MEM;
610 bytes_per_row = 2*((bmheader->w+15)/16);
612 for (y=0;y<bmheader->h;y++) {
614 rowptr = &bmheader->raw_data[y * bytes_per_row * bmheader->nplanes];
616 for (x=0,checkmask=0x80;x<bmheader->w;x++) {
620 for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) {
622 if (rowptr[bytes_per_row * p + byteofs] & checkmask)
628 *destptr++ = newbyte;
630 if ((checkmask >>= 1) == 0) checkmask=0x80;
635 d_free(bmheader->raw_data);
636 bmheader->raw_data = new_data;
638 bmheader->type = TYPE_PBM;
643 #define INDEX_TO_15BPP(i) ((short)((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31)))
645 int convert_rgb15(grs_bitmap *bm,iff_bitmap_header *bmheader)
652 palptr = bmheader->palette;
654 // if ((new_data = d_malloc(bm->bm_w * bm->bm_h * 2)) == NULL)
655 // {ret=IFF_NO_MEM; goto done;}
656 MALLOC(new_data, ushort, bm->bm_w * bm->bm_h * 2);
657 if (new_data == NULL)
660 for (y=0; y<bm->bm_h; y++) {
662 for (x=0; x<bmheader->w; x++)
663 new_data[newptr++] = INDEX_TO_15BPP(bmheader->raw_data[y*bmheader->w+x]);
667 d_free(bm->bm_data); //get rid of old-style data
668 bm->bm_data = (ubyte *) new_data; //..and point to new data
670 bm->bm_rowsize *= 2; //two bytes per row
676 //read in a entire file into a fake file structure
677 int open_fake_file(char *ifilename,FFILE *ffile)
682 //printf( "Reading %s\n", ifilename );
686 if ((ifile = cfopen(ifilename,"rb")) == NULL) return IFF_NO_FILE;
688 ffile->length = cfilelength(ifile);
690 MALLOC(ffile->data,ubyte,ffile->length);
692 if (cfread(ffile->data, 1, ffile->length, ifile) < ffile->length)
693 ret = IFF_READ_ERROR;
699 if (ifile) cfclose(ifile);
704 void close_fake_file(FFILE *f)
712 //copy an iff header structure to a grs_bitmap structure
713 void copy_iff_to_grs(grs_bitmap *bm,iff_bitmap_header *bmheader)
715 bm->bm_x = bm->bm_y = 0;
716 bm->bm_w = bmheader->w;
717 bm->bm_h = bmheader->h;
718 bm->bm_type = bmheader->type;
719 bm->bm_rowsize = bmheader->w;
720 bm->bm_data = bmheader->raw_data;
722 bm->bm_flags = bm->bm_handle = 0;
726 //if bm->bm_data is set, use it (making sure w & h are correct), else
727 //allocate the memory
728 int iff_parse_bitmap(FFILE *ifile,grs_bitmap *bm,int bitmap_type,byte *palette,grs_bitmap *prev_bm)
730 int ret; //return code
731 iff_bitmap_header bmheader;
735 bmheader.raw_data = bm->bm_data;
737 if (bmheader.raw_data) {
738 bmheader.w = bm->bm_w;
739 bmheader.h = bm->bm_h;
744 if (sig != form_sig) {
749 form_len = get_long(ifile);
751 form_type = get_sig(ifile);
753 if (form_type == anim_sig)
755 else if ((form_type == pbm_sig) || (form_type == ilbm_sig))
756 ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm);
758 ret = IFF_UNKNOWN_FORM;
760 if (ret != IFF_NO_ERROR) { //got an error parsing
761 if (bmheader.raw_data) d_free(bmheader.raw_data);
765 //If IFF file is ILBM, convert to PPB
766 if (bmheader.type == TYPE_ILBM) {
768 ret = convert_ilbm_to_pbm(&bmheader);
770 if (ret != IFF_NO_ERROR) goto done;
773 //Copy data from iff_bitmap_header structure into grs_bitmap structure
775 copy_iff_to_grs(bm,&bmheader);
778 if (palette) memcpy(palette,&bmheader.palette,sizeof(bmheader.palette));
780 // if (palette) memcpy(palette,&bmheader.palette, 768); // pal_entry is 4 bytes on mac
786 for (i = 0; i < 256; i++) {
787 *c++ = bmheader.palette[i].r;
788 *c++ = bmheader.palette[i].g;
789 *c++ = bmheader.palette[i].b;
794 //Now do post-process if required
796 if (bitmap_type == BM_RGB15) {
797 ret = convert_rgb15(bm,&bmheader);
798 if (ret != IFF_NO_ERROR) goto done;
807 //returns error codes - see IFF.H. see GR.H for bitmap_type
808 int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,ubyte *palette)
810 int ret; //return code
813 ret = open_fake_file(ifilename,&ifile); //read in entire file
814 if (ret != IFF_NO_ERROR) goto done;
818 ret = iff_parse_bitmap(&ifile,bm,bitmap_type,palette,NULL);
822 if (ifile.data) d_free(ifile.data);
824 close_fake_file(&ifile);
831 //like iff_read_bitmap(), but reads into a bitmap that already exists,
832 //without allocating memory for the bitmap.
833 int iff_read_into_bitmap(char *ifilename,grs_bitmap *bm,byte *palette)
835 int ret; //return code
838 ret = open_fake_file(ifilename,&ifile); //read in entire file
839 if (ret != IFF_NO_ERROR) goto done;
841 ret = iff_parse_bitmap(&ifile,bm,bm->bm_type,palette,NULL);
845 if (ifile.data) d_free(ifile.data);
847 close_fake_file(&ifile);
856 int write_bmhd(FILE *ofile,iff_bitmap_header *bitmap_header)
858 put_sig(bmhd_sig,ofile);
859 put_long((long) BMHD_SIZE,ofile);
861 put_word(bitmap_header->w,ofile);
862 put_word(bitmap_header->h,ofile);
863 put_word(bitmap_header->x,ofile);
864 put_word(bitmap_header->y,ofile);
866 put_byte(bitmap_header->nplanes,ofile);
867 put_byte(bitmap_header->masking,ofile);
868 put_byte(bitmap_header->compression,ofile);
869 put_byte(0,ofile); /* pad */
871 put_word(bitmap_header->transparentcolor,ofile);
872 put_byte(bitmap_header->xaspect,ofile);
873 put_byte(bitmap_header->yaspect,ofile);
875 put_word(bitmap_header->pagewidth,ofile);
876 put_word(bitmap_header->pageheight,ofile);
882 int write_pal(FILE *ofile,iff_bitmap_header *bitmap_header)
886 int n_colors = 1<<bitmap_header->nplanes;
888 put_sig(cmap_sig,ofile);
889 // put_long(sizeof(pal_entry) * n_colors,ofile);
890 put_long(3 * n_colors,ofile);
892 //printf("new write pal %d %d\n",3,n_colors);
894 for (i=0; i<256; i++) {
896 r = bitmap_header->palette[i].r * 4 + (bitmap_header->palette[i].r?3:0);
897 g = bitmap_header->palette[i].g * 4 + (bitmap_header->palette[i].g?3:0);
898 b = bitmap_header->palette[i].b * 4 + (bitmap_header->palette[i].b?3:0);
904 //printf("write pal %d %d\n",sizeof(pal_entry),n_colors);
905 // fwrite(bitmap_header->palette,sizeof(pal_entry),n_colors,ofile);
910 int rle_span(ubyte *dest,ubyte *src,int len)
912 int n,lit_cnt,rep_cnt;
913 ubyte last,*cnt_ptr,*dptr;
917 last=src[0]; lit_cnt=1;
919 for (n=1;n<len;n++) {
921 if (src[n] == last) {
926 while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;}
928 if (rep_cnt > 2 || lit_cnt < 2) {
930 if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;} //save old lit count
931 *dptr++ = -(rep_cnt-1);
934 lit_cnt = (n<len)?1:0;
936 continue; //go to next char
944 cnt_ptr = dptr++; //save place for count
945 *dptr++=last; //store first char
948 *dptr++ = last = src[n];
950 if (lit_cnt == 127) {
964 *dptr++=last; //store first char
966 else if (lit_cnt > 1)
967 *cnt_ptr = lit_cnt-1;
972 #define EVEN(a) ((a+1)&0xfffffffel)
974 //returns length of chunk
975 int write_body(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
977 int w=bitmap_header->w,h=bitmap_header->h;
979 long len = EVEN(w) * h,newlen,total_len=0;
980 ubyte *p=bitmap_header->raw_data,*new_span;
983 put_sig(body_sig,ofile);
984 save_pos = ftell(ofile);
987 //if (! (new_span = d_malloc(bitmap_header->w+(bitmap_header->w/128+2)*2))) return IFF_NO_MEM;
988 MALLOC( new_span, ubyte, bitmap_header->w + (bitmap_header->w/128+2)*2);
989 if (new_span == NULL) return IFF_NO_MEM;
991 for (y=bitmap_header->h;y--;) {
993 if (compression_on) {
994 total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd);
995 fwrite(new_span,newlen,1,ofile);
998 fwrite(p,bitmap_header->w+odd,1,ofile);
1000 p+=bitmap_header->row_size; //bitmap_header->w;
1003 if (compression_on) { //write actual data length
1004 Assert(fseek(ofile,save_pos,SEEK_SET)==0);
1005 put_long(total_len,ofile);
1006 Assert(fseek(ofile,total_len,SEEK_CUR)==0);
1007 if (total_len&1) fputc(0,ofile); //pad to even
1012 return ((compression_on) ? (EVEN(total_len)+8) : (len+8));
1017 //write a small representation of a bitmap. returns size
1018 int write_tiny(CFILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
1022 int len,total_len=0,newlen;
1024 ubyte *p = bitmap_header->raw_data;
1025 ubyte tspan[80],new_span[80*2];
1028 skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64);
1030 new_w = bitmap_header->w / skip;
1031 new_h = bitmap_header->h / skip;
1035 len = new_w * new_h + 4;
1037 put_sig(tiny_sig,ofile);
1038 save_pos = cftell(ofile);
1039 put_long(EVEN(len),ofile);
1041 put_word(new_w,ofile);
1042 put_word(new_h,ofile);
1044 for (y=0;y<new_h;y++) {
1045 for (x=xofs=0;x<new_w;x++,xofs+=skip)
1048 if (compression_on) {
1049 total_len += newlen = rle_span(new_span,tspan,new_w+odd);
1050 fwrite(new_span,newlen,1,ofile);
1053 fwrite(p,new_w+odd,1,ofile);
1055 p += skip * bitmap_header->row_size; //bitmap_header->w;
1059 if (compression_on) {
1060 Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
1061 put_long(4+total_len,ofile);
1062 Assert(cfseek(ofile,4+total_len,SEEK_CUR)==0);
1063 if (total_len&1) cfputc(0,ofile); //pad to even
1066 return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8));
1070 int write_pbm(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on) /* writes a pbm iff file */
1073 long raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
1074 long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
1077 //printf("write_pbm\n");
1079 put_sig(form_sig,ofile);
1080 save_pos = ftell(ofile);
1081 put_long(pbm_size+8,ofile);
1082 put_sig(pbm_sig,ofile);
1084 ret = write_bmhd(ofile,bitmap_header);
1085 if (ret != IFF_NO_ERROR) return ret;
1087 ret = write_pal(ofile,bitmap_header);
1088 if (ret != IFF_NO_ERROR) return ret;
1091 tiny_size = write_tiny(ofile,bitmap_header,compression_on);
1096 body_size = write_body(ofile,bitmap_header,compression_on);
1098 pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
1100 Assert(fseek(ofile,save_pos,SEEK_SET)==0);
1101 put_long(pbm_size+8,ofile);
1102 Assert(fseek(ofile,pbm_size+8,SEEK_CUR)==0);
1108 //writes an IFF file from a grs_bitmap structure. writes palette if not null
1109 //returns error codes - see IFF.H.
1110 int iff_write_bitmap(char *ofilename,grs_bitmap *bm,ubyte *palette)
1113 iff_bitmap_header bmheader;
1117 if (bm->bm_type == BM_RGB15) return IFF_BAD_BM_TYPE;
1120 compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH);
1125 //fill in values in bmheader
1127 bmheader.x = bmheader.y = 0;
1128 bmheader.w = bm->bm_w;
1129 bmheader.h = bm->bm_h;
1130 bmheader.type = TYPE_PBM;
1131 bmheader.transparentcolor = iff_transparent_color;
1132 bmheader.pagewidth = bm->bm_w; //I don't think it matters what I write
1133 bmheader.pageheight = bm->bm_h;
1134 bmheader.nplanes = 8;
1135 bmheader.masking = mskNone;
1136 if (iff_has_transparency) {
1137 bmheader.masking |= mskHasTransparentColor;
1139 bmheader.compression = (compression_on?cmpByteRun1:cmpNone);
1141 bmheader.xaspect = bmheader.yaspect = 1; //I don't think it matters what I write
1142 bmheader.raw_data = bm->bm_data;
1143 bmheader.row_size = bm->bm_rowsize;
1145 if (palette) memcpy(&bmheader.palette,palette,256*3);
1147 //open file and write
1149 if ((ofile = fopen(ofilename,"wb")) == NULL) {ret=IFF_NO_FILE; goto done;}
1151 ret = write_pbm(ofile,&bmheader,compression_on);
1160 //read in many brushes. fills in array of pointers, and n_bitmaps.
1161 //returns iff error codes
1162 int iff_read_animbrush(char *ifilename,grs_bitmap **bm_list,int max_bitmaps,int *n_bitmaps,ubyte *palette)
1164 int ret; //return code
1166 iff_bitmap_header bmheader;
1172 ret = open_fake_file(ifilename,&ifile); //read in entire file
1173 if (ret != IFF_NO_ERROR) goto done;
1175 bmheader.raw_data = NULL;
1177 sig=get_sig(&ifile);
1178 form_len = get_long(&ifile);
1180 if (sig != form_sig) {
1185 form_type = get_sig(&ifile);
1187 if ((form_type == pbm_sig) || (form_type == ilbm_sig))
1188 ret = IFF_FORM_BITMAP;
1189 else if (form_type == anim_sig) {
1190 int anim_end = ifile.position + form_len - 4;
1192 while (ifile.position < anim_end && *n_bitmaps < max_bitmaps) {
1194 grs_bitmap *prev_bm;
1196 prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1]:NULL;
1198 MALLOC(bm_list[*n_bitmaps] , grs_bitmap, 1 );
1200 bm_list[*n_bitmaps]->bm_data = NULL;
1202 ret = iff_parse_bitmap(&ifile,bm_list[*n_bitmaps],form_type,*n_bitmaps>0?NULL:palette,prev_bm);
1204 if (ret != IFF_NO_ERROR)
1210 if (ifile.position < anim_end) //ran out of room
1211 ret = IFF_TOO_MANY_BMS;
1215 ret = IFF_UNKNOWN_FORM;
1219 close_fake_file(&ifile);
1225 //text for error messges
1226 char error_messages[] = {
1228 "Not enough mem for loading or processing bitmap.\0"
1229 "IFF file has unknown FORM type.\0"
1230 "Not an IFF file.\0"
1231 "Cannot open file.\0"
1232 "Tried to save invalid type, like BM_RGB15.\0"
1233 "Bad data in file.\0"
1234 "ANIM file cannot be loaded with normal bitmap loader.\0"
1235 "Normal bitmap file cannot be loaded with anim loader.\0"
1236 "Array not big enough on anim brush read.\0"
1237 "Unknown mask type in bitmap header.\0"
1238 "Error reading file.\0"
1242 //function to return pointer to error message
1243 char *iff_errormsg(int error_number)
1245 char *p = error_messages;
1247 while (error_number--) {
1249 if (!p) return NULL;