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.2 2001-01-20 13:49:14 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;
281 end_pos = ifile->position + len;
285 if (bmheader->type == TYPE_PBM) {
288 } else if (bmheader->type == TYPE_ILBM) {
289 width = (bmheader->w+7)/8;
290 depth=bmheader->nplanes;
293 end_cnt = (width&1)?-1:0;
295 data_end = p + width*bmheader->h*depth;
297 if (bmheader->compression == cmpNone) { /* no compression */
300 for (y=bmheader->h;y;y--) {
302 // for (x=bmheader->w;x;x--) *p++=cfgetc(ifile);
303 // cfread(p, bmheader->w, 1, ifile);
306 for (x=0;x<width*depth;x++)
307 *p++=ifile->data[ifile->position++];
309 if (bmheader->masking == mskHasMask)
310 ifile->position += width; //skip mask!
312 // if (bmheader->w & 1) ignore = cfgetc(ifile);
313 if (bmheader->w & 1) ifile->position++;
316 //cnt = len - bmheader->h * ((bmheader->w+1)&~1);
319 else if (bmheader->compression == cmpByteRun1)
320 for (wid_cnt=width,plane=0;ifile->position<end_pos && p<data_end;) {
323 // if (old_cnt-cnt > 2048) {
328 if (wid_cnt == end_cnt) {
331 if ((bmheader->masking == mskHasMask && plane==depth+1) ||
332 (bmheader->masking != mskHasMask && plane==depth))
336 Assert(wid_cnt > end_cnt);
339 n=ifile->data[ifile->position++];
341 if (n >= 0) { // copy next n+1 bytes from source, they are not compressed
344 if (wid_cnt==-1) {--nn; Assert(width&1);}
345 if (plane==depth) //masking row
346 ifile->position += nn;
348 while (nn--) *p++=ifile->data[ifile->position++];
349 if (wid_cnt==-1) ifile->position++;
351 else if (n>=-127) { // next -n + 1 bytes are following byte
352 c=ifile->data[ifile->position++];
355 if (wid_cnt==-1) {--nn; Assert(width&1);}
356 if (plane!=depth) //not masking row
357 {memset(p,c,nn); p+=nn;}
361 if ((p-bmheader->raw_data) % width == 0)
364 Assert((p-bmheader->raw_data) - (width*row_count) < width);
369 if (p!=data_end) //if we don't have the whole bitmap...
370 return IFF_CORRUPT; //...the give an error
372 //Pretend we read the whole chuck, because if we didn't, it's because
373 //we didn't read the last mask like or the last rle record for padding
374 //or whatever and it's not important, because we check to make sure
375 //we got the while bitmap, and that's what really counts.
377 ifile->position = end_pos;
379 if (ignore) ignore++; // haha, suppress the evil warning message
384 //modify passed bitmap
385 int parse_delta(FFILE *ifile,long len,iff_bitmap_header *bmheader)
387 unsigned char *p=bmheader->raw_data;
389 long chunk_end = ifile->position + len;
391 get_long(ifile); //longword, seems to be equal to 4. Don't know what it is
393 for (y=0;y<bmheader->h;y++) {
395 int cnt = bmheader->w;
398 n_items = get_byte(ifile);
402 code = get_byte(ifile);
404 if (code==0) { //repeat
407 rep = get_byte(ifile);
408 val = get_byte(ifile);
416 else if (code > 0x80) { //skip
428 *p++ = get_byte(ifile);
444 if (ifile->position == chunk_end-1) //pad
447 if (ifile->position != chunk_end)
453 // the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
454 void skip_chunk(FFILE *ifile,long len)
460 //printf( "Skipping %d chunk\n", ilen );
462 ifile->position += ilen;
464 if (ifile->position >= ifile->length ) {
465 ifile->position = ifile->length;
469 // for (i=0; i<ilen; i++ )
470 // c = cfgetc(ifile);
471 //Assert(cfseek(ifile,ilen,SEEK_CUR)==0);
474 //read an ILBM or PBM file
475 // Pass pointer to opened file, and to empty bitmap_header structure, and form length
476 int iff_parse_ilbm_pbm(FFILE *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm)
480 long start_pos,end_pos;
482 start_pos = ifile->position;
483 end_pos = start_pos-4+form_len;
485 // printf(" %ld ",form_len);
486 // printsig(form_type);
489 if (form_type == pbm_sig)
490 bmheader->type = TYPE_PBM;
492 bmheader->type = TYPE_ILBM;
494 while ((ifile->position < end_pos) && (sig=get_sig(ifile)) != EOF) {
501 // printf(" %ld\n",len);
507 int save_w=bmheader->w,save_h=bmheader->h;
509 //printf("Parsing header\n");
511 ret = parse_bmhd(ifile,len,bmheader);
513 if (ret != IFF_NO_ERROR)
516 if (bmheader->raw_data) {
518 if (save_w != bmheader->w || save_h != bmheader->h)
519 return IFF_BM_MISMATCH;
524 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
525 if (!bmheader->raw_data)
535 if (!prev_bm) return IFF_CORRUPT;
537 bmheader->w = prev_bm->bm_w;
538 bmheader->h = prev_bm->bm_h;
539 bmheader->type = prev_bm->bm_type;
541 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
543 memcpy(bmheader->raw_data, prev_bm->bm_data, bmheader->w * bmheader->h );
544 skip_chunk(ifile,len);
550 int ncolors=(int) (len/3),cnum;
553 //printf("Parsing RGB map\n");
554 for (cnum=0;cnum<ncolors;cnum++) {
558 r = ifile->data[ifile->position++];
559 g = ifile->data[ifile->position++];
560 b = ifile->data[ifile->position++];
561 r >>= 2; bmheader->palette[cnum].r = r;
562 g >>= 2; bmheader->palette[cnum].g = g;
563 b >>= 2; bmheader->palette[cnum].b = b;
565 //if (len & 1) ignore = cfgetc(ifile);
566 if (len & 1 ) ifile->position++;
574 //printf("Parsing body\n");
575 if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR)
582 if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR)
587 skip_chunk(ifile,len);
592 //if (ignore) ignore++;
594 if (ifile->position != start_pos-4+form_len)
597 return IFF_NO_ERROR; /* ok! */
600 //convert an ILBM file to a PBM file
601 int convert_ilbm_to_pbm(iff_bitmap_header *bmheader)
604 byte *new_data,*destptr,*rowptr;
605 int bytes_per_row,byteofs;
606 ubyte checkmask,newbyte,setbit;
608 MALLOC( new_data, byte, bmheader->w * bmheader->h );
609 if (new_data == NULL) return IFF_NO_MEM;
613 bytes_per_row = 2*((bmheader->w+15)/16);
615 for (y=0;y<bmheader->h;y++) {
617 rowptr = &bmheader->raw_data[y * bytes_per_row * bmheader->nplanes];
619 for (x=0,checkmask=0x80;x<bmheader->w;x++) {
623 for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) {
625 if (rowptr[bytes_per_row * p + byteofs] & checkmask)
631 *destptr++ = newbyte;
633 if ((checkmask >>= 1) == 0) checkmask=0x80;
638 d_free(bmheader->raw_data);
639 bmheader->raw_data = new_data;
641 bmheader->type = TYPE_PBM;
646 #define INDEX_TO_15BPP(i) ((short)((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31)))
648 int convert_rgb15(grs_bitmap *bm,iff_bitmap_header *bmheader)
655 palptr = bmheader->palette;
657 // if ((new_data = d_malloc(bm->bm_w * bm->bm_h * 2)) == NULL)
658 // {ret=IFF_NO_MEM; goto done;}
659 MALLOC(new_data, ushort, bm->bm_w * bm->bm_h * 2);
660 if (new_data == NULL)
663 for (y=0; y<bm->bm_h; y++) {
665 for (x=0; x<bmheader->w; x++)
666 new_data[newptr++] = INDEX_TO_15BPP(bmheader->raw_data[y*bmheader->w+x]);
670 d_free(bm->bm_data); //get rid of old-style data
671 bm->bm_data = (ubyte *) new_data; //..and point to new data
673 bm->bm_rowsize *= 2; //two bytes per row
679 //read in a entire file into a fake file structure
680 int open_fake_file(char *ifilename,FFILE *ffile)
685 //printf( "Reading %s\n", ifilename );
689 if ((ifile = cfopen(ifilename,"rb")) == NULL) return IFF_NO_FILE;
691 ffile->length = cfilelength(ifile);
693 MALLOC(ffile->data,ubyte,ffile->length);
695 if (cfread(ffile->data, 1, ffile->length, ifile) < ffile->length)
696 ret = IFF_READ_ERROR;
702 if (ifile) cfclose(ifile);
707 void close_fake_file(FFILE *f)
715 //copy an iff header structure to a grs_bitmap structure
716 void copy_iff_to_grs(grs_bitmap *bm,iff_bitmap_header *bmheader)
718 bm->bm_x = bm->bm_y = 0;
719 bm->bm_w = bmheader->w;
720 bm->bm_h = bmheader->h;
721 bm->bm_type = bmheader->type;
722 bm->bm_rowsize = bmheader->w;
723 bm->bm_data = bmheader->raw_data;
725 bm->bm_flags = bm->bm_handle = 0;
729 //if bm->bm_data is set, use it (making sure w & h are correct), else
730 //allocate the memory
731 int iff_parse_bitmap(FFILE *ifile,grs_bitmap *bm,int bitmap_type,byte *palette,grs_bitmap *prev_bm)
733 int ret; //return code
734 iff_bitmap_header bmheader;
738 bmheader.raw_data = bm->bm_data;
740 if (bmheader.raw_data) {
741 bmheader.w = bm->bm_w;
742 bmheader.h = bm->bm_h;
747 if (sig != form_sig) {
752 form_len = get_long(ifile);
754 form_type = get_sig(ifile);
756 if (form_type == anim_sig)
758 else if ((form_type == pbm_sig) || (form_type == ilbm_sig))
759 ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm);
761 ret = IFF_UNKNOWN_FORM;
763 if (ret != IFF_NO_ERROR) { //got an error parsing
764 if (bmheader.raw_data) d_free(bmheader.raw_data);
768 //If IFF file is ILBM, convert to PPB
769 if (bmheader.type == TYPE_ILBM) {
771 ret = convert_ilbm_to_pbm(&bmheader);
773 if (ret != IFF_NO_ERROR) goto done;
776 //Copy data from iff_bitmap_header structure into grs_bitmap structure
778 copy_iff_to_grs(bm,&bmheader);
781 if (palette) memcpy(palette,&bmheader.palette,sizeof(bmheader.palette));
783 // if (palette) memcpy(palette,&bmheader.palette, 768); // pal_entry is 4 bytes on mac
789 for (i = 0; i < 256; i++) {
790 *c++ = bmheader.palette[i].r;
791 *c++ = bmheader.palette[i].g;
792 *c++ = bmheader.palette[i].b;
797 //Now do post-process if required
799 if (bitmap_type == BM_RGB15) {
800 ret = convert_rgb15(bm,&bmheader);
801 if (ret != IFF_NO_ERROR) goto done;
810 //returns error codes - see IFF.H. see GR.H for bitmap_type
811 int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,ubyte *palette)
813 int ret; //return code
816 ret = open_fake_file(ifilename,&ifile); //read in entire file
817 if (ret != IFF_NO_ERROR) goto done;
821 ret = iff_parse_bitmap(&ifile,bm,bitmap_type,palette,NULL);
825 if (ifile.data) d_free(ifile.data);
827 close_fake_file(&ifile);
834 //like iff_read_bitmap(), but reads into a bitmap that already exists,
835 //without allocating memory for the bitmap.
836 int iff_read_into_bitmap(char *ifilename,grs_bitmap *bm,byte *palette)
838 int ret; //return code
841 ret = open_fake_file(ifilename,&ifile); //read in entire file
842 if (ret != IFF_NO_ERROR) goto done;
844 ret = iff_parse_bitmap(&ifile,bm,bm->bm_type,palette,NULL);
848 if (ifile.data) d_free(ifile.data);
850 close_fake_file(&ifile);
859 int write_bmhd(FILE *ofile,iff_bitmap_header *bitmap_header)
861 put_sig(bmhd_sig,ofile);
862 put_long((long) BMHD_SIZE,ofile);
864 put_word(bitmap_header->w,ofile);
865 put_word(bitmap_header->h,ofile);
866 put_word(bitmap_header->x,ofile);
867 put_word(bitmap_header->y,ofile);
869 put_byte(bitmap_header->nplanes,ofile);
870 put_byte(bitmap_header->masking,ofile);
871 put_byte(bitmap_header->compression,ofile);
872 put_byte(0,ofile); /* pad */
874 put_word(bitmap_header->transparentcolor,ofile);
875 put_byte(bitmap_header->xaspect,ofile);
876 put_byte(bitmap_header->yaspect,ofile);
878 put_word(bitmap_header->pagewidth,ofile);
879 put_word(bitmap_header->pageheight,ofile);
885 int write_pal(FILE *ofile,iff_bitmap_header *bitmap_header)
889 int n_colors = 1<<bitmap_header->nplanes;
891 put_sig(cmap_sig,ofile);
892 // put_long(sizeof(pal_entry) * n_colors,ofile);
893 put_long(3 * n_colors,ofile);
895 //printf("new write pal %d %d\n",3,n_colors);
897 for (i=0; i<256; i++) {
899 r = bitmap_header->palette[i].r * 4 + (bitmap_header->palette[i].r?3:0);
900 g = bitmap_header->palette[i].g * 4 + (bitmap_header->palette[i].g?3:0);
901 b = bitmap_header->palette[i].b * 4 + (bitmap_header->palette[i].b?3:0);
907 //printf("write pal %d %d\n",sizeof(pal_entry),n_colors);
908 // fwrite(bitmap_header->palette,sizeof(pal_entry),n_colors,ofile);
913 int rle_span(ubyte *dest,ubyte *src,int len)
915 int n,lit_cnt,rep_cnt;
916 ubyte last,*cnt_ptr,*dptr;
922 last=src[0]; lit_cnt=1;
924 for (n=1;n<len;n++) {
926 if (src[n] == last) {
931 while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;}
933 if (rep_cnt > 2 || lit_cnt < 2) {
935 if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;} //save old lit count
936 *dptr++ = -(rep_cnt-1);
939 lit_cnt = (n<len)?1:0;
941 continue; //go to next char
949 cnt_ptr = dptr++; //save place for count
950 *dptr++=last; //store first char
953 *dptr++ = last = src[n];
955 if (lit_cnt == 127) {
969 *dptr++=last; //store first char
971 else if (lit_cnt > 1)
972 *cnt_ptr = lit_cnt-1;
977 #define EVEN(a) ((a+1)&0xfffffffel)
979 //returns length of chunk
980 int write_body(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
982 int w=bitmap_header->w,h=bitmap_header->h;
984 long len = EVEN(w) * h,newlen,total_len=0;
985 ubyte *p=bitmap_header->raw_data,*new_span;
988 put_sig(body_sig,ofile);
989 save_pos = ftell(ofile);
992 //if (! (new_span = d_malloc(bitmap_header->w+(bitmap_header->w/128+2)*2))) return IFF_NO_MEM;
993 MALLOC( new_span, ubyte, bitmap_header->w + (bitmap_header->w/128+2)*2);
994 if (new_span == NULL) return IFF_NO_MEM;
996 for (y=bitmap_header->h;y--;) {
998 if (compression_on) {
999 total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd);
1000 fwrite(new_span,newlen,1,ofile);
1003 fwrite(p,bitmap_header->w+odd,1,ofile);
1005 p+=bitmap_header->row_size; //bitmap_header->w;
1008 if (compression_on) { //write actual data length
1009 Assert(fseek(ofile,save_pos,SEEK_SET)==0);
1010 put_long(total_len,ofile);
1011 Assert(fseek(ofile,total_len,SEEK_CUR)==0);
1012 if (total_len&1) fputc(0,ofile); //pad to even
1017 return ((compression_on) ? (EVEN(total_len)+8) : (len+8));
1022 //write a small representation of a bitmap. returns size
1023 int write_tiny(CFILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
1027 int len,total_len=0,newlen;
1029 ubyte *p = bitmap_header->raw_data;
1030 ubyte tspan[80],new_span[80*2];
1033 skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64);
1035 new_w = bitmap_header->w / skip;
1036 new_h = bitmap_header->h / skip;
1040 len = new_w * new_h + 4;
1042 put_sig(tiny_sig,ofile);
1043 save_pos = cftell(ofile);
1044 put_long(EVEN(len),ofile);
1046 put_word(new_w,ofile);
1047 put_word(new_h,ofile);
1049 for (y=0;y<new_h;y++) {
1050 for (x=xofs=0;x<new_w;x++,xofs+=skip)
1053 if (compression_on) {
1054 total_len += newlen = rle_span(new_span,tspan,new_w+odd);
1055 fwrite(new_span,newlen,1,ofile);
1058 fwrite(p,new_w+odd,1,ofile);
1060 p += skip * bitmap_header->row_size; //bitmap_header->w;
1064 if (compression_on) {
1065 Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
1066 put_long(4+total_len,ofile);
1067 Assert(cfseek(ofile,4+total_len,SEEK_CUR)==0);
1068 if (total_len&1) cfputc(0,ofile); //pad to even
1071 return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8));
1075 int write_pbm(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on) /* writes a pbm iff file */
1078 long raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
1079 long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
1082 //printf("write_pbm\n");
1084 put_sig(form_sig,ofile);
1085 save_pos = ftell(ofile);
1086 put_long(pbm_size+8,ofile);
1087 put_sig(pbm_sig,ofile);
1089 ret = write_bmhd(ofile,bitmap_header);
1090 if (ret != IFF_NO_ERROR) return ret;
1092 ret = write_pal(ofile,bitmap_header);
1093 if (ret != IFF_NO_ERROR) return ret;
1096 tiny_size = write_tiny(ofile,bitmap_header,compression_on);
1101 body_size = write_body(ofile,bitmap_header,compression_on);
1103 pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
1105 Assert(fseek(ofile,save_pos,SEEK_SET)==0);
1106 put_long(pbm_size+8,ofile);
1107 Assert(fseek(ofile,pbm_size+8,SEEK_CUR)==0);
1113 //writes an IFF file from a grs_bitmap structure. writes palette if not null
1114 //returns error codes - see IFF.H.
1115 int iff_write_bitmap(char *ofilename,grs_bitmap *bm,ubyte *palette)
1118 iff_bitmap_header bmheader;
1122 if (bm->bm_type == BM_RGB15) return IFF_BAD_BM_TYPE;
1125 compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH);
1130 //fill in values in bmheader
1132 bmheader.x = bmheader.y = 0;
1133 bmheader.w = bm->bm_w;
1134 bmheader.h = bm->bm_h;
1135 bmheader.type = TYPE_PBM;
1136 bmheader.transparentcolor = iff_transparent_color;
1137 bmheader.pagewidth = bm->bm_w; //I don't think it matters what I write
1138 bmheader.pageheight = bm->bm_h;
1139 bmheader.nplanes = 8;
1140 bmheader.masking = mskNone;
1141 if (iff_has_transparency) {
1142 bmheader.masking |= mskHasTransparentColor;
1144 bmheader.compression = (compression_on?cmpByteRun1:cmpNone);
1146 bmheader.xaspect = bmheader.yaspect = 1; //I don't think it matters what I write
1147 bmheader.raw_data = bm->bm_data;
1148 bmheader.row_size = bm->bm_rowsize;
1150 if (palette) memcpy(&bmheader.palette,palette,256*3);
1152 //open file and write
1154 if ((ofile = fopen(ofilename,"wb")) == NULL) {ret=IFF_NO_FILE; goto done;}
1156 ret = write_pbm(ofile,&bmheader,compression_on);
1165 //read in many brushes. fills in array of pointers, and n_bitmaps.
1166 //returns iff error codes
1167 int iff_read_animbrush(char *ifilename,grs_bitmap **bm_list,int max_bitmaps,int *n_bitmaps,ubyte *palette)
1169 int ret; //return code
1171 iff_bitmap_header bmheader;
1177 ret = open_fake_file(ifilename,&ifile); //read in entire file
1178 if (ret != IFF_NO_ERROR) goto done;
1180 bmheader.raw_data = NULL;
1182 sig=get_sig(&ifile);
1183 form_len = get_long(&ifile);
1185 if (sig != form_sig) {
1190 form_type = get_sig(&ifile);
1192 if ((form_type == pbm_sig) || (form_type == ilbm_sig))
1193 ret = IFF_FORM_BITMAP;
1194 else if (form_type == anim_sig) {
1195 int anim_end = ifile.position + form_len - 4;
1197 while (ifile.position < anim_end && *n_bitmaps < max_bitmaps) {
1199 grs_bitmap *prev_bm;
1201 prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1]:NULL;
1203 MALLOC(bm_list[*n_bitmaps] , grs_bitmap, 1 );
1205 bm_list[*n_bitmaps]->bm_data = NULL;
1207 ret = iff_parse_bitmap(&ifile,bm_list[*n_bitmaps],form_type,*n_bitmaps>0?NULL:palette,prev_bm);
1209 if (ret != IFF_NO_ERROR)
1215 if (ifile.position < anim_end) //ran out of room
1216 ret = IFF_TOO_MANY_BMS;
1220 ret = IFF_UNKNOWN_FORM;
1224 close_fake_file(&ifile);
1230 //text for error messges
1231 char error_messages[] = {
1233 "Not enough mem for loading or processing bitmap.\0"
1234 "IFF file has unknown FORM type.\0"
1235 "Not an IFF file.\0"
1236 "Cannot open file.\0"
1237 "Tried to save invalid type, like BM_RGB15.\0"
1238 "Bad data in file.\0"
1239 "ANIM file cannot be loaded with normal bitmap loader.\0"
1240 "Normal bitmap file cannot be loaded with anim loader.\0"
1241 "Array not big enough on anim brush read.\0"
1242 "Unknown mask type in bitmap header.\0"
1243 "Error reading file.\0"
1247 //function to return pointer to error message
1248 char *iff_errormsg(int error_number)
1250 char *p = error_messages;
1252 while (error_number--) {
1254 if (!p) return NULL;