]> icculus.org git repositories - btb/d2x.git/blob - main/piggy.c
more header fixes
[btb/d2x.git] / main / piggy.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  * Functions for managing the pig files.
17  *
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "strutil.h"
30 #include "inferno.h"
31 #include "gr.h"
32 #include "grdef.h"
33 #include "u_mem.h"
34 #include "iff.h"
35 #include "mono.h"
36 #include "error.h"
37 #include "hash.h"
38 #include "args.h"
39 #include "palette.h"
40 #include "rle.h"
41 #include "cfile.h"
42 #include "byteswap.h"
43 #include "makesig.h"
44
45 #ifndef MACINTOSH
46 //      #include "unarj.h"
47 #else
48         #include <Strings.h>            // MacOS Toolbox header
49         #include <Files.h>
50         #include <unistd.h>
51 #endif
52
53
54 //#define NO_DUMP_SOUNDS        1   //if set, dump bitmaps but not sounds
55
56 #define DEFAULT_PIGFILE_REGISTERED      "groupa.pig"
57 #define DEFAULT_PIGFILE_SHAREWARE       "d2demo.pig"
58 #define DEFAULT_HAMFILE_REGISTERED      "descent2.ham"
59 #define DEFAULT_HAMFILE_SHAREWARE       "d2demo.ham"
60
61 #define D1_PALETTE "palette.256"
62
63 #define DEFAULT_PIGFILE (cfexist(DEFAULT_PIGFILE_REGISTERED)?DEFAULT_PIGFILE_REGISTERED:DEFAULT_PIGFILE_SHAREWARE)
64 #define DEFAULT_HAMFILE (cfexist(DEFAULT_HAMFILE_REGISTERED)?DEFAULT_HAMFILE_REGISTERED:DEFAULT_HAMFILE_SHAREWARE)
65 #define DEFAULT_SNDFILE ((Piggy_hamfile_version < 3)?DEFAULT_HAMFILE_SHAREWARE:(digi_sample_rate==SAMPLE_RATE_22K)?"descent2.s22":"descent2.s11")
66
67 #define MAC_ALIEN1_PIGSIZE      5013035
68 #define MAC_ALIEN2_PIGSIZE      4909916
69 #define MAC_FIRE_PIGSIZE        4969035
70 #define MAC_GROUPA_PIGSIZE      4929684 // also used for mac shareware
71 #define MAC_ICE_PIGSIZE         4923425
72 #define MAC_WATER_PIGSIZE       4832403
73
74 ubyte *BitmapBits = NULL;
75 ubyte *SoundBits = NULL;
76
77 typedef struct BitmapFile {
78         char    name[15];
79 } BitmapFile;
80
81 typedef struct SoundFile {
82         char    name[15];
83 } SoundFile;
84
85 hashtable AllBitmapsNames;
86 hashtable AllDigiSndNames;
87
88 int Num_bitmap_files = 0;
89 int Num_sound_files = 0;
90
91 digi_sound GameSounds[MAX_SOUND_FILES];
92 int SoundOffset[MAX_SOUND_FILES];
93 grs_bitmap GameBitmaps[MAX_BITMAP_FILES];
94
95 alias alias_list[MAX_ALIASES];
96 int Num_aliases=0;
97
98 int Must_write_hamfile = 0;
99 int Num_bitmap_files_new = 0;
100 int Num_sound_files_new = 0;
101 BitmapFile AllBitmaps[ MAX_BITMAP_FILES ];
102 static SoundFile AllSounds[ MAX_SOUND_FILES ];
103
104 int Piggy_hamfile_version = 0;
105
106 int piggy_low_memory = 0;
107
108 int Piggy_bitmap_cache_size = 0;
109 int Piggy_bitmap_cache_next = 0;
110 ubyte * Piggy_bitmap_cache_data = NULL;
111 static int GameBitmapOffset[MAX_BITMAP_FILES];
112 static ubyte GameBitmapFlags[MAX_BITMAP_FILES];
113 ushort GameBitmapXlat[MAX_BITMAP_FILES];
114
115 #define PIGGY_BUFFER_SIZE (2400*1024)
116
117 #ifdef MACINTOSH
118 #define PIGGY_SMALL_BUFFER_SIZE (1400*1024)             // size of buffer when piggy_low_memory is set
119
120 #ifdef SHAREWARE
121 #undef PIGGY_BUFFER_SIZE
122 #undef PIGGY_SMALL_BUFFER_SIZE
123
124 #define PIGGY_BUFFER_SIZE (2000*1024)
125 #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024)
126 #endif          // SHAREWARE
127
128 #endif
129
130 int piggy_page_flushed = 0;
131
132 #define DBM_FLAG_ABM    64 // animated bitmap
133 #define DBM_NUM_FRAMES  63
134
135 #define BM_FLAGS_TO_COPY (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT \
136                          | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE | BM_FLAG_RLE_BIG)
137
138 typedef struct DiskBitmapHeader {
139         char name[8];
140         ubyte dflags;           // bits 0-5 anim frame num, bit 6 abm flag
141         ubyte width;            // low 8 bits here, 4 more bits in wh_extra
142         ubyte height;           // low 8 bits here, 4 more bits in wh_extra
143         ubyte wh_extra;         // bits 0-3 width, bits 4-7 height
144         ubyte flags;
145         ubyte avg_color;
146         int offset;
147 } __pack__ DiskBitmapHeader;
148
149 #define DISKBITMAPHEADER_D1_SIZE 17 // no wh_extra
150
151 typedef struct DiskSoundHeader {
152         char name[8];
153         int length;
154         int data_length;
155         int offset;
156 } __pack__ DiskSoundHeader;
157
158 #ifdef FAST_FILE_IO
159 #define DiskBitmapHeader_read(dbh, fp) cfread(dbh, sizeof(DiskBitmapHeader), 1, fp)
160 #define DiskSoundHeader_read(dsh, fp) cfread(dsh, sizeof(DiskSoundHeader), 1, fp)
161 #else
162 /*
163  * reads a DiskBitmapHeader structure from a CFILE
164  */
165 void DiskBitmapHeader_read(DiskBitmapHeader *dbh, CFILE *fp)
166 {
167         cfread(dbh->name, 8, 1, fp);
168         dbh->dflags = cfile_read_byte(fp);
169         dbh->width = cfile_read_byte(fp);
170         dbh->height = cfile_read_byte(fp);
171         dbh->wh_extra = cfile_read_byte(fp);
172         dbh->flags = cfile_read_byte(fp);
173         dbh->avg_color = cfile_read_byte(fp);
174         dbh->offset = cfile_read_int(fp);
175 }
176
177 /*
178  * reads a DiskSoundHeader structure from a CFILE
179  */
180 void DiskSoundHeader_read(DiskSoundHeader *dsh, CFILE *fp)
181 {
182         cfread(dsh->name, 8, 1, fp);
183         dsh->length = cfile_read_int(fp);
184         dsh->data_length = cfile_read_int(fp);
185         dsh->offset = cfile_read_int(fp);
186 }
187 #endif // FAST_FILE_IO
188
189 /*
190  * reads a descent 1 DiskBitmapHeader structure from a CFILE
191  */
192 void DiskBitmapHeader_d1_read(DiskBitmapHeader *dbh, CFILE *fp)
193 {
194         cfread(dbh->name, 8, 1, fp);
195         dbh->dflags = cfile_read_byte(fp);
196         dbh->width = cfile_read_byte(fp);
197         dbh->height = cfile_read_byte(fp);
198         dbh->wh_extra = 0;
199         dbh->flags = cfile_read_byte(fp);
200         dbh->avg_color = cfile_read_byte(fp);
201         dbh->offset = cfile_read_int(fp);
202 }
203
204 ubyte BigPig = 0;
205
206 #ifdef MACINTOSH
207         extern short    cd_VRefNum;
208         extern void             ConcatPStr(StringPtr dst, StringPtr src);
209         extern int              ConvertPToCStr(StringPtr inPStr, char* outCStrBuf);
210         extern int              ConvertCToPStr(char* inCStr, StringPtr outPStrBuf);
211 #endif
212
213 int piggy_is_substitutable_bitmap( char * name, char * subst_name );
214
215 #ifdef EDITOR
216 void piggy_write_pigfile(char *filename);
217 static void write_int(int i,FILE *file);
218 #endif
219
220 void swap_0_255(grs_bitmap *bmp)
221 {
222         int i;
223
224         for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) {
225                 if(bmp->bm_data[i] == 0)
226                         bmp->bm_data[i] = 255;
227                 else if (bmp->bm_data[i] == 255)
228                         bmp->bm_data[i] = 0;
229         }
230 }
231
232 char* piggy_game_bitmap_name(grs_bitmap *bmp)
233 {
234         if (bmp >= GameBitmaps && bmp < &GameBitmaps[MAX_BITMAP_FILES])
235         {
236                 int i = (int)(bmp - GameBitmaps); // i = (bmp - GameBitmaps) / sizeof(grs_bitmap);
237                 Assert (bmp == &GameBitmaps[i] && i >= 0 && i < MAX_BITMAP_FILES);
238                 return AllBitmaps[i].name;
239         }
240         return NULL;
241 }
242
243 bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file )
244 {
245         bitmap_index temp;
246         Assert( Num_bitmap_files < MAX_BITMAP_FILES );
247
248         temp.index = Num_bitmap_files;
249
250         if (!in_file)   {
251 #ifdef EDITOR
252                 if ( FindArg("-macdata") )
253                         swap_0_255( bmp );
254 #endif
255                 if ( !BigPig )  gr_bitmap_rle_compress( bmp );
256                 Num_bitmap_files_new++;
257         }
258
259         strncpy( AllBitmaps[Num_bitmap_files].name, name, 12 );
260         hashtable_insert( &AllBitmapsNames, AllBitmaps[Num_bitmap_files].name, Num_bitmap_files );
261         //GameBitmaps[Num_bitmap_files] = *bmp;
262         if ( !in_file ) {
263                 GameBitmapOffset[Num_bitmap_files] = 0;
264                 GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags;
265         }
266         Num_bitmap_files++;
267
268         return temp;
269 }
270
271 int piggy_register_sound( digi_sound * snd, char * name, int in_file )
272 {
273         int i;
274
275         Assert( Num_sound_files < MAX_SOUND_FILES );
276
277         strncpy( AllSounds[Num_sound_files].name, name, 12 );
278         hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files );
279         GameSounds[Num_sound_files] = *snd;
280         if ( !in_file ) {
281                 SoundOffset[Num_sound_files] = 0;       
282         }
283
284         i = Num_sound_files;
285    
286         if (!in_file)
287                 Num_sound_files_new++;
288
289         Num_sound_files++;
290         return i;
291 }
292
293 bitmap_index piggy_find_bitmap( char * name )   
294 {
295         bitmap_index bmp;
296         int i;
297         char *t;
298
299         bmp.index = 0;
300
301         if ((t=strchr(name,'#'))!=NULL)
302                 *t=0;
303
304         for (i=0;i<Num_aliases;i++)
305                 if (stricmp(name,alias_list[i].alias_name)==0) {
306                         if (t) {                //extra stuff for ABMs
307                                 static char temp[FILENAME_LEN];
308                                 _splitpath(alias_list[i].file_name, NULL, NULL, temp, NULL );
309                                 name = temp;
310                                 strcat(name,"#");
311                                 strcat(name,t+1);
312                         }
313                         else
314                                 name=alias_list[i].file_name; 
315                         break;
316                 }
317
318         if (t)
319                 *t = '#';
320
321         i = hashtable_search( &AllBitmapsNames, name );
322         Assert( i != 0 );
323         if ( i < 0 )
324                 return bmp;
325
326         bmp.index = i;
327         return bmp;
328 }
329
330 int piggy_find_sound( char * name )     
331 {
332         int i;
333
334         i = hashtable_search( &AllDigiSndNames, name );
335
336         if ( i < 0 )
337                 return 255;
338
339         return i;
340 }
341
342 CFILE * Piggy_fp = NULL;
343
344 #define FILENAME_LEN 13
345
346 char Current_pigfile[FILENAME_LEN] = "";
347
348 void piggy_close_file()
349 {
350         if ( Piggy_fp ) {
351                 cfclose( Piggy_fp );
352                 Piggy_fp        = NULL;
353                 Current_pigfile[0] = 0;
354         }
355 }
356
357 int Pigfile_initialized=0;
358
359 #define PIGFILE_ID              MAKE_SIG('G','I','P','P') //PPIG
360 #define PIGFILE_VERSION         2
361
362
363 //initialize a pigfile, reading headers
364 //returns the size of all the bitmap data
365 void piggy_init_pigfile(char *filename)
366 {
367         int i;
368         char temp_name[16];
369         char temp_name_read[16];
370         DiskBitmapHeader bmh;
371         int header_size, N_bitmaps, data_size, data_start;
372
373         piggy_close_file();             //close old pig if still open
374
375         //rename pigfile for shareware
376         if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(filename))
377                 filename = DEFAULT_PIGFILE_SHAREWARE;
378
379                 Piggy_fp = cfopen( filename, "rb" );
380
381 #if defined(MACINTOSH) && defined(SHAREWARE) // if we are in the shareware version, we must have the pig by now.
382                         if (Piggy_fp == NULL)
383                         {
384                                 Error("Cannot load required file <%s>",name);
385                         }
386 #endif  // end of if def shareware
387
388         if (!Piggy_fp) {
389                 #ifdef EDITOR
390                         return;         //if editor, ok to not have pig, because we'll build one
391                 #else
392                         Piggy_fp = cfopen(filename, "rb");
393                 #endif
394         }
395
396         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
397                 int pig_id,pig_version;
398
399                 pig_id = cfile_read_int(Piggy_fp);
400                 pig_version = cfile_read_int(Piggy_fp);
401                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
402                         cfclose(Piggy_fp);              //out of date pig
403                         Piggy_fp = NULL;                        //..so pretend it's not here
404                 }
405         }
406
407         if (!Piggy_fp) {
408
409                 #ifdef EDITOR
410                         return;         //if editor, ok to not have pig, because we'll build one
411                 #else
412                         Error("Cannot load required file <%s>",filename);
413                 #endif
414         }
415
416         strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
417
418         N_bitmaps = cfile_read_int(Piggy_fp);
419
420         header_size = N_bitmaps * sizeof(DiskBitmapHeader);
421
422         data_start = header_size + cftell(Piggy_fp);
423
424         data_size = cfilelength(Piggy_fp) - data_start;
425
426         Num_bitmap_files = 1;
427
428         for (i=0; i<N_bitmaps; i++ )
429     {
430                 int width;
431                 grs_bitmap *bm = &GameBitmaps[i + 1];
432                 
433                 DiskBitmapHeader_read(&bmh, Piggy_fp);
434                 memcpy( temp_name_read, bmh.name, 8 );
435                 temp_name_read[8] = 0;
436                 if ( bmh.dflags & DBM_FLAG_ABM )        
437                         sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & DBM_NUM_FRAMES );
438                 else
439                         strcpy( temp_name, temp_name_read );
440                 width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
441                 gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
442                 bm->bm_flags = BM_FLAG_PAGED_OUT;
443                 bm->avg_color = bmh.avg_color;
444
445                 GameBitmapFlags[i+1] = bmh.flags & BM_FLAGS_TO_COPY;
446
447                 GameBitmapOffset[i+1] = bmh.offset + data_start;
448                 Assert( (i+1) == Num_bitmap_files );
449                 piggy_register_bitmap(bm, temp_name, 1);
450         }
451
452 #ifdef EDITOR
453         Piggy_bitmap_cache_size = data_size + (data_size/10);   //extra mem for new bitmaps
454         Assert( Piggy_bitmap_cache_size > 0 );
455 #else
456         Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
457         #ifdef MACINTOSH
458         if (piggy_low_memory)
459                 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
460         #endif
461 #endif
462         BitmapBits = d_malloc( Piggy_bitmap_cache_size );
463         if ( BitmapBits == NULL )
464                 Error( "Not enough memory to load bitmaps\n" );
465         Piggy_bitmap_cache_data = BitmapBits;
466         Piggy_bitmap_cache_next = 0;
467
468         #if defined(MACINTOSH) && defined(SHAREWARE)
469 //      load_exit_models();
470         #endif
471
472         Pigfile_initialized=1;
473 }
474
475 #define FILENAME_LEN 13
476 #define MAX_BITMAPS_PER_BRUSH 30
477
478 extern int compute_average_pixel(grs_bitmap *new);
479 extern void gr_set_bitmap_data(grs_bitmap *bm, unsigned char *data);
480
481 ubyte *Bitmap_replacement_data = NULL;
482
483 //reads in a new pigfile (for new palette)
484 //returns the size of all the bitmap data
485 void piggy_new_pigfile(char *pigname)
486 {
487         int i;
488         char temp_name[16];
489         char temp_name_read[16];
490         DiskBitmapHeader bmh;
491         int header_size, N_bitmaps, data_size, data_start;
492         int must_rewrite_pig = 0;
493
494         strlwr(pigname);
495
496         //rename pigfile for shareware
497         if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(pigname))
498                 pigname = DEFAULT_PIGFILE_SHAREWARE;
499
500         if (strnicmp(Current_pigfile, pigname, sizeof(Current_pigfile)) == 0 // correct pig already loaded
501             && !Bitmap_replacement_data) // no need to reload: no bitmaps were altered
502                 return;
503
504         if (!Pigfile_initialized) {                     //have we ever opened a pigfile?
505                 piggy_init_pigfile(pigname);            //..no, so do initialization stuff
506                 return;
507         }
508         else
509                 piggy_close_file();             //close old pig if still open
510
511         Piggy_bitmap_cache_next = 0;            //free up cache
512
513         strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
514
515                 Piggy_fp = cfopen( pigname, "rb" );
516
517 #if defined(MACINTOSH) && defined(SHAREWARE) // if we are in the shareware version, we must have the pig by now.
518                         if (Piggy_fp == NULL)
519                         {
520                                 Error("Cannot load required file <%s>",name);
521                         }
522 #endif  // end of if def shareware
523
524         #ifndef EDITOR
525         if (!Piggy_fp)
526                 Piggy_fp = cfopen(pigname, "rb");
527         #endif
528
529         if (Piggy_fp) {  //make sure pig is valid type file & is up-to-date
530                 int pig_id,pig_version;
531
532                 pig_id = cfile_read_int(Piggy_fp);
533                 pig_version = cfile_read_int(Piggy_fp);
534                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
535                         cfclose(Piggy_fp);              //out of date pig
536                         Piggy_fp = NULL;                        //..so pretend it's not here
537                 }
538         }
539
540 #ifndef EDITOR
541         if (!Piggy_fp)
542                 Error("Cannot open correct version of <%s>", pigname);
543 #endif
544
545         if (Piggy_fp) {
546
547                 N_bitmaps = cfile_read_int(Piggy_fp);
548
549                 header_size = N_bitmaps * sizeof(DiskBitmapHeader);
550
551                 data_start = header_size + cftell(Piggy_fp);
552
553                 data_size = cfilelength(Piggy_fp) - data_start;
554
555                 for (i=1; i<=N_bitmaps; i++ )
556                 {
557                         grs_bitmap *bm = &GameBitmaps[i];
558                         int width;
559                         
560                         DiskBitmapHeader_read(&bmh, Piggy_fp);
561                         memcpy( temp_name_read, bmh.name, 8 );
562                         temp_name_read[8] = 0;
563         
564                         if ( bmh.dflags & DBM_FLAG_ABM )        
565                                 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & DBM_NUM_FRAMES );
566                         else
567                                 strcpy( temp_name, temp_name_read );
568         
569                         //Make sure name matches
570                         if (strcmp(temp_name,AllBitmaps[i].name)) {
571                                 //Int3();       //this pig is out of date.  Delete it
572                                 must_rewrite_pig=1;
573                         }
574         
575                         strcpy(AllBitmaps[i].name,temp_name);
576
577                         width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
578                         gr_set_bitmap_data(bm, NULL);   // free ogl texture
579                         gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
580                         bm->bm_flags = BM_FLAG_PAGED_OUT;
581                         bm->avg_color = bmh.avg_color;
582
583                         GameBitmapFlags[i] = bmh.flags & BM_FLAGS_TO_COPY;
584         
585                         GameBitmapOffset[i] = bmh.offset + data_start;
586                 }
587         }
588         else
589                 N_bitmaps = 0;          //no pigfile, so no bitmaps
590
591         #ifndef EDITOR
592
593         Assert(N_bitmaps == Num_bitmap_files-1);
594
595         #else
596
597         if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
598                 int size;
599
600                 //re-read the bitmaps that aren't in this pig
601
602                 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
603                         char *p;
604
605                         p = strchr(AllBitmaps[i].name,'#');
606
607                         if (p) {   // this is an ABM == animated bitmap
608                                 char abmname[FILENAME_LEN];
609                                 int fnum;
610                                 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
611                                 int iff_error;          //reference parm to avoid warning message
612                                 ubyte newpal[768];
613                                 char basename[FILENAME_LEN];
614                                 int nframes;
615                         
616                                 strcpy(basename,AllBitmaps[i].name);
617                                 basename[p-AllBitmaps[i].name] = 0;  //cut off "#nn" part
618                                 
619                                 sprintf( abmname, "%s.abm", basename );
620
621                                 iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
622
623                                 if (iff_error != IFF_NO_ERROR)  {
624                                         mprintf((1,"File %s - IFF error: %s",abmname,iff_errormsg(iff_error)));
625                                         Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
626                                 }
627                         
628                                 for (fnum=0;fnum<nframes; fnum++)       {
629                                         char tempname[20];
630                                         int SuperX;
631
632                                         sprintf( tempname, "%s#%d", basename, fnum );
633
634                                         //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
635                                         SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
636                                         //above makes assumption that supertransparent color is 254
637
638                                         if ( iff_has_transparency )
639                                                 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
640                                         else
641                                                 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
642
643                                         bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
644
645 #ifdef EDITOR
646                                         if ( FindArg("-macdata") )
647                                                 swap_0_255( bm[fnum] );
648 #endif
649                                         if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
650
651                                         if (bm[fnum]->bm_flags & BM_FLAG_RLE)
652                                                 size = *((int *) bm[fnum]->bm_data);
653                                         else
654                                                 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
655
656                                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
657                                         d_free(bm[fnum]->bm_data);
658                                         bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
659                                         Piggy_bitmap_cache_next += size;
660
661                                         GameBitmaps[i+fnum] = *bm[fnum];
662
663                                         // -- mprintf( (0, "U" ));
664                                         d_free( bm[fnum] );
665                                 }
666
667                                 i += nframes-1;         //filled in multiple bitmaps
668                         }
669                         else {          //this is a BBM
670
671                                 grs_bitmap * new;
672                                 ubyte newpal[256*3];
673                                 int iff_error;
674                                 char bbmname[FILENAME_LEN];
675                                 int SuperX;
676
677                                 MALLOC( new, grs_bitmap, 1 );
678
679                                 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
680                                 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
681
682                                 new->bm_handle=0;
683                                 if (iff_error != IFF_NO_ERROR)          {
684                                         mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)));
685                                         Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
686                                 }
687
688                                 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
689                                 //above makes assumption that supertransparent color is 254
690
691                                 if ( iff_has_transparency )
692                                         gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
693                                 else
694                                         gr_remap_bitmap_good( new, newpal, -1, SuperX );
695
696                                 new->avg_color = compute_average_pixel(new);
697
698 #ifdef EDITOR
699                                 if ( FindArg("-macdata") )
700                                         swap_0_255( new );
701 #endif
702                                 if ( !BigPig )  gr_bitmap_rle_compress( new );
703
704                                 if (new->bm_flags & BM_FLAG_RLE)
705                                         size = *((int *) new->bm_data);
706                                 else
707                                         size = new->bm_w * new->bm_h;
708
709                                 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size);
710                                 d_free(new->bm_data);
711                                 new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
712                                 Piggy_bitmap_cache_next += size;
713
714                                 GameBitmaps[i] = *new;
715         
716                                 d_free( new );
717
718                                 // -- mprintf( (0, "U" ));
719                         }
720                 }
721
722                 //@@Dont' do these things which are done when writing
723                 //@@for (i=0; i < Num_bitmap_files; i++ )       {
724                 //@@    bitmap_index bi;
725                 //@@    bi.index = i;
726                 //@@    PIGGY_PAGE_IN( bi );
727                 //@@}
728                 //@@
729                 //@@piggy_close_file();
730
731                 piggy_write_pigfile(pigname);
732
733                 Current_pigfile[0] = 0;                 //say no pig, to force reload
734
735                 piggy_new_pigfile(pigname);             //read in just-generated pig
736
737
738         }
739         #endif  //ifdef EDITOR
740
741 }
742
743 ubyte bogus_data[64*64];
744 ubyte bogus_bitmap_initialized=0;
745 digi_sound bogus_sound;
746
747 #define HAMFILE_ID              MAKE_SIG('!','M','A','H') //HAM!
748 #define HAMFILE_VERSION 3
749 //version 1 -> 2:  save marker_model_num
750 //version 2 -> 3:  removed sound files
751
752 #define SNDFILE_ID              MAKE_SIG('D','N','S','D') //DSND
753 #define SNDFILE_VERSION 1
754
755 int read_hamfile()
756 {
757         CFILE * ham_fp = NULL;
758         int ham_id;
759         int sound_offset = 0;
760
761         ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
762
763         if (ham_fp == NULL) {
764                 Must_write_hamfile = 1;
765                 return 0;
766         }
767
768         //make sure ham is valid type file & is up-to-date
769         ham_id = cfile_read_int(ham_fp);
770         Piggy_hamfile_version = cfile_read_int(ham_fp);
771         if (ham_id != HAMFILE_ID)
772                 Error("Cannot open ham file %s\n", DEFAULT_HAMFILE);
773 #if 0
774         if (ham_id != HAMFILE_ID || Piggy_hamfile_version != HAMFILE_VERSION) {
775                 Must_write_hamfile = 1;
776                 cfclose(ham_fp);                                                //out of date ham
777                 return 0;
778         }
779 #endif
780
781         if (Piggy_hamfile_version < 3) // hamfile contains sound info
782                 sound_offset = cfile_read_int(ham_fp);
783
784         #if 1 //ndef EDITOR
785         {
786                 //int i;
787
788                 bm_read_all(ham_fp);
789                 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
790                 // no swap here?
791                 //for (i = 0; i < MAX_BITMAP_FILES; i++) {
792                         //GameBitmapXlat[i] = INTEL_SHORT(GameBitmapXlat[i]);
793                         //printf("GameBitmapXlat[%d] = %d\n", i, GameBitmapXlat[i]);
794                 //}
795         }
796         #endif
797
798         if (Piggy_hamfile_version < 3) {
799                 int N_sounds;
800                 int sound_start;
801                 int header_size;
802                 int i;
803                 DiskSoundHeader sndh;
804                 digi_sound temp_sound;
805                 char temp_name_read[16];
806                 int sbytes = 0;
807
808                 cfseek(ham_fp, sound_offset, SEEK_SET);
809                 N_sounds = cfile_read_int(ham_fp);
810
811                 sound_start = cftell(ham_fp);
812
813                 header_size = N_sounds * sizeof(DiskSoundHeader);
814
815                 //Read sounds
816
817                 for (i=0; i<N_sounds; i++ ) {
818                         DiskSoundHeader_read(&sndh, ham_fp);
819                         temp_sound.length = sndh.length;
820                         temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
821                         SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
822                         memcpy( temp_name_read, sndh.name, 8 );
823                         temp_name_read[8] = 0;
824                         piggy_register_sound( &temp_sound, temp_name_read, 1 );
825 #ifdef MACINTOSH
826                         if (piggy_is_needed(i))
827 #endif          // note link to if.
828                                 sbytes += sndh.length;
829                         //mprintf(( 0, "%d bytes of sound\n", sbytes ));
830                 }
831
832                 SoundBits = d_malloc( sbytes + 16 );
833                 if ( SoundBits == NULL )
834                         Error( "Not enough memory to load sounds\n" );
835
836                 mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
837
838                 //      piggy_read_sounds(ham_fp);
839
840         }
841
842         cfclose(ham_fp);
843
844         return 1;
845
846 }
847
848 int read_sndfile()
849 {
850         CFILE * snd_fp = NULL;
851         int snd_id,snd_version;
852         int N_sounds;
853         int sound_start;
854         int header_size;
855         int i,size, length;
856         DiskSoundHeader sndh;
857         digi_sound temp_sound;
858         char temp_name_read[16];
859         int sbytes = 0;
860
861         snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
862         
863         if (snd_fp == NULL)
864                 return 0;
865
866         //make sure soundfile is valid type file & is up-to-date
867         snd_id = cfile_read_int(snd_fp);
868         snd_version = cfile_read_int(snd_fp);
869         if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) {
870                 cfclose(snd_fp);                                                //out of date sound file
871                 return 0;
872         }
873
874         N_sounds = cfile_read_int(snd_fp);
875
876         sound_start = cftell(snd_fp);
877         size = cfilelength(snd_fp) - sound_start;
878         length = size;
879         mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
880
881         header_size = N_sounds*sizeof(DiskSoundHeader);
882
883         //Read sounds
884
885         for (i=0; i<N_sounds; i++ ) {
886                 DiskSoundHeader_read(&sndh, snd_fp);
887                 //size -= sizeof(DiskSoundHeader);
888                 temp_sound.length = sndh.length;
889                 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
890                 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
891                 memcpy( temp_name_read, sndh.name, 8 );
892                 temp_name_read[8] = 0;
893                 piggy_register_sound( &temp_sound, temp_name_read, 1 );
894                 #ifdef MACINTOSH
895                 if (piggy_is_needed(i))
896                 #endif          // note link to if.
897                 sbytes += sndh.length;
898                 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
899         }
900
901         SoundBits = d_malloc( sbytes + 16 );
902         if ( SoundBits == NULL )
903                 Error( "Not enough memory to load sounds\n" );
904
905         mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
906
907 //      piggy_read_sounds(snd_fp);
908
909         cfclose(snd_fp);
910
911         return 1;
912 }
913
914 int piggy_init(void)
915 {
916         int ham_ok=0,snd_ok=0;
917         int i;
918
919         hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
920         hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
921
922         for (i=0; i<MAX_SOUND_FILES; i++ )      {
923                 GameSounds[i].length = 0;
924                 GameSounds[i].data = NULL;
925                 SoundOffset[i] = 0;
926         }
927
928         for (i=0; i<MAX_BITMAP_FILES; i++ )     
929                 GameBitmapXlat[i] = i;
930
931         if ( !bogus_bitmap_initialized )        {
932                 int i;
933                 ubyte c;
934
935                 bogus_bitmap_initialized = 1;
936                 c = gr_find_closest_color( 0, 0, 63 );
937                 for (i=0; i<4096; i++ ) bogus_data[i] = c;
938                 c = gr_find_closest_color( 63, 0, 0 );
939                 // Make a big red X !
940                 for (i=0; i<64; i++ )   {
941                         bogus_data[i*64+i] = c;
942                         bogus_data[i*64+(63-i)] = c;
943                 }
944                 gr_init_bitmap(&GameBitmaps[Num_bitmap_files], 0, 0, 0, 64, 64, 64, bogus_data);
945                 piggy_register_bitmap(&GameBitmaps[Num_bitmap_files], "bogus", 1);
946                 bogus_sound.length = 64*64;
947                 bogus_sound.data = bogus_data;
948                 GameBitmapOffset[0] = 0;
949         }
950
951         if ( FindArg( "-bigpig" ))
952                 BigPig = 1;
953
954         if ( FindArg( "-lowmem" ))
955                 piggy_low_memory = 1;
956
957         if ( FindArg( "-nolowmem" ))
958                 piggy_low_memory = 0;
959
960         if (piggy_low_memory)
961                 digi_lomem = 1;
962
963                 gr_set_curfont( SMALL_FONT );
964                 gr_set_fontcolor(gr_find_closest_color_current( 20, 20, 20 ),-1 );
965                 gr_printf( 0x8000, grd_curcanv->cv_h-20, "%s...", TXT_LOADING_DATA );
966
967 #if 1 //def EDITOR //need for d1 mission briefings
968         piggy_init_pigfile(DEFAULT_PIGFILE);
969 #endif
970
971         snd_ok = ham_ok = read_hamfile();
972
973         if (Piggy_hamfile_version >= 3)
974                 snd_ok = read_sndfile();
975
976         atexit(piggy_close);
977
978         mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
979         return (ham_ok && snd_ok);               //read ok
980 }
981
982 int piggy_is_needed(int soundnum)
983 {
984         int i;
985
986         if ( !digi_lomem ) return 1;
987
988         for (i=0; i<MAX_SOUNDS; i++ )   {
989                 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
990                         return 1;
991         }
992         return 0;
993 }
994
995
996 void piggy_read_sounds(void)
997 {
998         CFILE * fp = NULL;
999         ubyte * ptr;
1000         int i, sbytes;
1001
1002         ptr = SoundBits;
1003         sbytes = 0;
1004
1005         fp = cfopen( DEFAULT_SNDFILE, "rb" );
1006
1007         if (fp == NULL)
1008                 return;
1009
1010         for (i=0; i<Num_sound_files; i++ )      {
1011                 digi_sound *snd = &GameSounds[i];
1012
1013                 if ( SoundOffset[i] > 0 )       {
1014                         if ( piggy_is_needed(i) )       {
1015                                 cfseek( fp, SoundOffset[i], SEEK_SET );
1016
1017                                 // Read in the sound data!!!
1018                                 snd->data = ptr;
1019                                 ptr += snd->length;
1020                                 sbytes += snd->length;
1021                                 cfread( snd->data, snd->length, 1, fp );
1022                         }
1023                         else
1024                                 snd->data = (ubyte *) -1;
1025                 }
1026         }
1027
1028         cfclose(fp);
1029
1030         mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1031
1032 }
1033
1034
1035 extern int descent_critical_error;
1036 extern unsigned descent_critical_deverror;
1037 extern unsigned descent_critical_errcode;
1038
1039 char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \
1040 "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \
1041 "Read fault", "General Failure" };
1042
1043 void piggy_critical_error()
1044 {
1045         grs_canvas * save_canv;
1046         grs_font * save_font;
1047         int i;
1048         save_canv = grd_curcanv;
1049         save_font = grd_curcanv->cv_font;
1050         gr_palette_load( gr_palette );
1051         i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A'  );
1052         if ( i == 1 )
1053                 exit(1);
1054         gr_set_current_canvas(save_canv);
1055         grd_curcanv->cv_font = save_font;
1056 }
1057
1058 extern void gr_set_bitmap_flags(grs_bitmap *pbm, int flags);
1059
1060 void piggy_bitmap_page_in( bitmap_index bitmap )
1061 {
1062         grs_bitmap * bmp;
1063         int i,org_i,temp;
1064
1065         org_i = 0;
1066
1067         i = bitmap.index;
1068         Assert( i >= 0 );
1069         Assert( i < MAX_BITMAP_FILES );
1070         Assert( i < Num_bitmap_files );
1071         Assert( Piggy_bitmap_cache_size > 0 );
1072
1073         if ( i < 1 ) return;
1074         if ( i >= MAX_BITMAP_FILES ) return;
1075         if ( i >= Num_bitmap_files ) return;
1076
1077         if ( GameBitmapOffset[i] == 0 ) return;         // A read-from-disk bitmap!!!
1078
1079         if ( piggy_low_memory ) {
1080                 org_i = i;
1081                 i = GameBitmapXlat[i];          // Xlat for low-memory settings!
1082         }
1083
1084         bmp = &GameBitmaps[i];
1085
1086         if ( bmp->bm_flags & BM_FLAG_PAGED_OUT )        {
1087                 stop_time();
1088
1089         ReDoIt:
1090                 descent_critical_error = 0;
1091                 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1092                 if ( descent_critical_error )   {
1093                         piggy_critical_error();
1094                         goto ReDoIt;
1095                 }
1096
1097                 gr_set_bitmap_flags(bmp, GameBitmapFlags[i]);
1098
1099                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1100                         int zsize = 0, pigsize = cfilelength(Piggy_fp);
1101                         descent_critical_error = 0;
1102                         zsize = cfile_read_int(Piggy_fp);
1103                         if ( descent_critical_error )   {
1104                                 piggy_critical_error();
1105                                 goto ReDoIt;
1106                         }
1107
1108                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1109                         //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
1110                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1111                                 Int3();
1112                                 piggy_bitmap_page_out_all();
1113                                 goto ReDoIt;
1114                         }
1115                         descent_critical_error = 0;
1116                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next+4], 1, zsize-4, Piggy_fp );
1117                         if ( descent_critical_error )   {
1118                                 piggy_critical_error();
1119                                 goto ReDoIt;
1120                         }
1121                         *((int *) (Piggy_bitmap_cache_data + Piggy_bitmap_cache_next)) = INTEL_INT(zsize);
1122                         gr_set_bitmap_data(bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
1123
1124 #ifndef MACDATA
1125                         switch (pigsize) {
1126                         default:
1127                                 if (!FindArg("-macdata"))
1128                                         break;
1129                                 // otherwise, fall through...
1130                         case MAC_ALIEN1_PIGSIZE:
1131                         case MAC_ALIEN2_PIGSIZE:
1132                         case MAC_FIRE_PIGSIZE:
1133                         case MAC_GROUPA_PIGSIZE:
1134                         case MAC_ICE_PIGSIZE:
1135                         case MAC_WATER_PIGSIZE:
1136                                 rle_swap_0_255( bmp );
1137                                 memcpy(&zsize, bmp->bm_data, 4);
1138                                 break;
1139                         }
1140 #endif
1141
1142                         Piggy_bitmap_cache_next += zsize;
1143                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1144                                 Int3();
1145                                 piggy_bitmap_page_out_all();
1146                                 goto ReDoIt;
1147                         }
1148
1149                 } else {
1150                         int pigsize = cfilelength(Piggy_fp);
1151                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1152                         Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
1153                         if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1154                                 piggy_bitmap_page_out_all();
1155                                 goto ReDoIt;
1156                         }
1157                         descent_critical_error = 0;
1158                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1159                         if ( descent_critical_error )   {
1160                                 piggy_critical_error();
1161                                 goto ReDoIt;
1162                         }
1163                         gr_set_bitmap_data(bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
1164                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1165
1166 #ifndef MACDATA
1167                         switch (pigsize) {
1168                         default:
1169                                 if (!FindArg("-macdata"))
1170                                         break;
1171                                 // otherwise, fall through...
1172                         case MAC_ALIEN1_PIGSIZE:
1173                         case MAC_ALIEN2_PIGSIZE:
1174                         case MAC_FIRE_PIGSIZE:
1175                         case MAC_GROUPA_PIGSIZE:
1176                         case MAC_ICE_PIGSIZE:
1177                         case MAC_WATER_PIGSIZE:
1178                                 swap_0_255( bmp );
1179                                 break;
1180                         }
1181 #endif
1182                 }
1183
1184                 //@@if ( bmp->bm_selector ) {
1185                 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1186                 //@@    if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1187                 //@@            Error( "Error modifying selector base in piggy.c\n" );
1188                 //@@#endif
1189                 //@@}
1190
1191                 start_time();
1192         }
1193
1194         if ( piggy_low_memory ) {
1195                 if ( org_i != i )
1196                         GameBitmaps[org_i] = GameBitmaps[i];
1197         }
1198
1199 //@@Removed from John's code:
1200 //@@#ifndef WINDOWS
1201 //@@    if ( bmp->bm_selector ) {
1202 //@@            if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1203 //@@                    Error( "Error modifying selector base in piggy.c\n" );
1204 //@@    }
1205 //@@#endif
1206
1207 }
1208
1209 void piggy_bitmap_page_out_all()
1210 {
1211         int i;
1212         
1213         Piggy_bitmap_cache_next = 0;
1214
1215         piggy_page_flushed++;
1216
1217         texmerge_flush();
1218         rle_cache_flush();
1219
1220         for (i=0; i<Num_bitmap_files; i++ )             {
1221                 if ( GameBitmapOffset[i] > 0 )  {       // Don't page out bitmaps read from disk!!!
1222                         GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1223                         gr_set_bitmap_data(&GameBitmaps[i], NULL);
1224                 }
1225         }
1226
1227         mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1228 }
1229
1230 void piggy_load_level_data()
1231 {
1232         piggy_bitmap_page_out_all();
1233         paging_touch_all();
1234 }
1235
1236 #ifdef EDITOR
1237
1238 void piggy_write_pigfile(char *filename)
1239 {
1240         FILE *pig_fp;
1241         int bitmap_data_start, data_offset;
1242         DiskBitmapHeader bmh;
1243         int org_offset;
1244         char subst_name[32];
1245         int i;
1246         FILE *fp1,*fp2;
1247         char tname[FILENAME_LEN];
1248
1249         // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1250         for (i=0; i < Num_bitmap_files; i++ )   {
1251                 bitmap_index bi;
1252                 bi.index = i;
1253                 PIGGY_PAGE_IN( bi );
1254         }
1255         // -- mprintf( (0, "\n" ));
1256
1257         piggy_close_file();
1258
1259         // -- mprintf( (0, "Creating %s...",filename ));
1260
1261         pig_fp = fopen( filename, "wb" );       //open PIG file
1262         Assert( pig_fp!=NULL );
1263
1264         write_int(PIGFILE_ID,pig_fp);
1265         write_int(PIGFILE_VERSION,pig_fp);
1266
1267         Num_bitmap_files--;
1268         fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1269         Num_bitmap_files++;
1270
1271         bitmap_data_start = ftell(pig_fp);
1272         bitmap_data_start += (Num_bitmap_files - 1) * sizeof(DiskBitmapHeader);
1273         data_offset = bitmap_data_start;
1274
1275         change_filename_extension(tname,filename,"lst");
1276         fp1 = fopen( tname, "wt" );
1277         change_filename_extension(tname,filename,"all");
1278         fp2 = fopen( tname, "wt" );
1279
1280         for (i=1; i < Num_bitmap_files; i++ )   {
1281                 int *size;
1282                 grs_bitmap *bmp;
1283
1284                 {               
1285                         char * p, *p1;
1286                         p = strchr(AllBitmaps[i].name, '#');
1287                         if (p) {   // this is an ABM == animated bitmap
1288                                 int n;
1289                                 p1 = p; p1++; 
1290                                 n = atoi(p1);
1291                                 *p = 0;
1292                                 if (fp2 && n==0)
1293                                         fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1294                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1295                                 Assert( n <= DBM_NUM_FRAMES );
1296                                 bmh.dflags = DBM_FLAG_ABM + n;
1297                                 *p = '#';
1298                         } else {
1299                                 if (fp2)
1300                                         fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1301                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1302                                 bmh.dflags = 0;
1303                         }
1304                 }
1305                 bmp = &GameBitmaps[i];
1306
1307                 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1308
1309                 if (fp1)
1310                         fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1311                 org_offset = ftell(pig_fp);
1312                 bmh.offset = data_offset - bitmap_data_start;
1313                 fseek( pig_fp, data_offset, SEEK_SET );
1314
1315                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1316                         size = (int *)bmp->bm_data;
1317                         fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1318                         data_offset += *size;
1319                         if (fp1)
1320                                 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1321                 } else {
1322                         fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1323                         data_offset += bmp->bm_rowsize * bmp->bm_h;
1324                         if (fp1)
1325                                 fprintf( fp1, ".\n" );
1326                 }
1327                 fseek( pig_fp, org_offset, SEEK_SET );
1328                 Assert( GameBitmaps[i].bm_w < 4096 );
1329                 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1330                 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1331                 Assert( GameBitmaps[i].bm_h < 4096 );
1332                 bmh.height = GameBitmaps[i].bm_h;
1333                 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1334                 bmh.flags = GameBitmaps[i].bm_flags;
1335                 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name ))    {
1336                         bitmap_index other_bitmap;
1337                         other_bitmap = piggy_find_bitmap( subst_name );
1338                         GameBitmapXlat[i] = other_bitmap.index;
1339                         bmh.flags |= BM_FLAG_PAGED_OUT;
1340                         //mprintf(( 0, "Skipping bitmap %d\n", i ));
1341                         //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1342                 } else  {
1343                         bmh.flags &= ~BM_FLAG_PAGED_OUT;
1344                 }
1345                 bmh.avg_color=GameBitmaps[i].avg_color;
1346                 fwrite(&bmh, sizeof(DiskBitmapHeader), 1, pig_fp);  // Mark as a bitmap
1347         }
1348
1349         fclose(pig_fp);
1350
1351         mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1352         fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1353
1354         fclose(fp1);
1355         fclose(fp2);
1356
1357 }
1358
1359 static void write_int(int i,FILE *file)
1360 {
1361         if (fwrite( &i, sizeof(i), 1, file) != 1)
1362                 Error( "Error reading int in gamesave.c" );
1363
1364 }
1365
1366 void piggy_dump_all()
1367 {
1368         int i, xlat_offset;
1369         FILE * ham_fp;
1370         int org_offset,data_offset=0;
1371         DiskSoundHeader sndh;
1372         int sound_data_start=0;
1373         FILE *fp1,*fp2;
1374
1375         #ifdef NO_DUMP_SOUNDS
1376         Num_sound_files = 0;
1377         Num_sound_files_new = 0;
1378         #endif
1379
1380         if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1381                 return;
1382
1383         fp1 = fopen( "ham.lst", "wt" );
1384         fp2 = fopen( "ham.all", "wt" );
1385
1386         if (Must_write_hamfile || Num_bitmap_files_new) {
1387
1388                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1389         
1390                 ham_fp = fopen( DEFAULT_HAMFILE, "wb" );                       //open HAM file
1391                 Assert( ham_fp!=NULL );
1392         
1393                 write_int(HAMFILE_ID,ham_fp);
1394                 write_int(HAMFILE_VERSION,ham_fp);
1395         
1396                 bm_write_all(ham_fp);
1397                 xlat_offset = ftell(ham_fp);
1398                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1399                 //Dump bitmaps
1400         
1401                 if (Num_bitmap_files_new)
1402                         piggy_write_pigfile(DEFAULT_PIGFILE);
1403         
1404                 //free up memeory used by new bitmaps
1405                 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1406                         d_free(GameBitmaps[i].bm_data);
1407         
1408                 //next thing must be done after pig written
1409                 fseek( ham_fp, xlat_offset, SEEK_SET );
1410                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1411         
1412                 fclose(ham_fp);
1413                 mprintf( (0, "\n" ));
1414         }
1415         
1416         if (Num_sound_files_new) {
1417
1418                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1419                 // Now dump sound file
1420                 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1421                 Assert( ham_fp!=NULL );
1422         
1423                 write_int(SNDFILE_ID,ham_fp);
1424                 write_int(SNDFILE_VERSION,ham_fp);
1425
1426                 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1427         
1428                 mprintf( (0, "\nDumping sounds..." ));
1429         
1430                 sound_data_start = ftell(ham_fp);
1431                 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1432                 data_offset = sound_data_start;
1433         
1434                 for (i=0; i < Num_sound_files; i++ )    {
1435                         digi_sound *snd;
1436         
1437                         snd = &GameSounds[i];
1438                         strcpy( sndh.name, AllSounds[i].name );
1439                         sndh.length = GameSounds[i].length;
1440                         sndh.offset = data_offset - sound_data_start;
1441         
1442                         org_offset = ftell(ham_fp);
1443                         fseek( ham_fp, data_offset, SEEK_SET );
1444         
1445                         sndh.data_length = GameSounds[i].length;
1446                         fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1447                         data_offset += snd->length;
1448                         fseek( ham_fp, org_offset, SEEK_SET );
1449                         fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp );                    // Mark as a bitmap
1450         
1451                         fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1452                         fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1453                 }
1454
1455                 fclose(ham_fp);
1456                 mprintf( (0, "\n" ));
1457         }
1458
1459         fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1460         mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1461         fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1462
1463         fclose(fp1);
1464         fclose(fp2);
1465
1466         // Never allow the game to run after building ham.
1467         exit(0);
1468 }
1469
1470 #endif
1471
1472 void piggy_close()
1473 {
1474         piggy_close_file();
1475
1476         if (BitmapBits)
1477                 d_free(BitmapBits);
1478
1479         if ( SoundBits )
1480                 d_free( SoundBits );
1481
1482         hashtable_free( &AllBitmapsNames );
1483         hashtable_free( &AllDigiSndNames );
1484
1485 }
1486
1487 int piggy_does_bitmap_exist_slow( char * name )
1488 {
1489         int i;
1490
1491         for (i=0; i<Num_bitmap_files; i++ )     {
1492                 if ( !strcmp( AllBitmaps[i].name, name) )
1493                         return 1;
1494         }
1495         return 0;
1496 }
1497
1498
1499 #define NUM_GAUGE_BITMAPS 23
1500 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1501         "gauge01", "gauge01b",
1502         "gauge02", "gauge02b",
1503         "gauge06", "gauge06b",
1504         "targ01", "targ01b",
1505         "targ02", "targ02b", 
1506         "targ03", "targ03b",
1507         "targ04", "targ04b",
1508         "targ05", "targ05b",
1509         "targ06", "targ06b",
1510         "gauge18", "gauge18b",
1511         "gauss1", "helix1",
1512         "phoenix1"
1513 };
1514
1515
1516 int piggy_is_gauge_bitmap( char * base_name )
1517 {
1518         int i;
1519         for (i=0; i<NUM_GAUGE_BITMAPS; i++ )    {
1520                 if ( !stricmp( base_name, gauge_bitmap_names[i] ))      
1521                         return 1;
1522         }
1523
1524         return 0;       
1525 }
1526
1527 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1528 {
1529         int frame;
1530         char * p;
1531         char base_name[ 16 ];
1532         
1533         strcpy( subst_name, name );
1534         p = strchr( subst_name, '#' );
1535         if ( p )        {
1536                 frame = atoi( &p[1] );
1537                 *p = 0;
1538                 strcpy( base_name, subst_name );
1539                 if ( !piggy_is_gauge_bitmap( base_name ))       {
1540                         sprintf( subst_name, "%s#%d", base_name, frame+1 );
1541                         if ( piggy_does_bitmap_exist_slow( subst_name )  )      {
1542                                 if ( frame & 1 ) {
1543                                         sprintf( subst_name, "%s#%d", base_name, frame-1 );
1544                                         return 1;
1545                                 }
1546                         }
1547                 }
1548         }
1549         strcpy( subst_name, name );
1550         return 0;
1551 }
1552
1553
1554
1555 /*
1556  * Functions for loading replacement textures
1557  *  1) From .pog files
1558  *  2) From descent.pig (for loading d1 levels)
1559  */
1560
1561 extern char last_palette_loaded_pig[];
1562
1563 void free_bitmap_replacements()
1564 {
1565         if (Bitmap_replacement_data) {
1566                 d_free(Bitmap_replacement_data);
1567                 Bitmap_replacement_data = NULL;
1568         }
1569 }
1570
1571 void load_bitmap_replacements(char *level_name)
1572 {
1573         char ifile_name[FILENAME_LEN];
1574         CFILE *ifile;
1575         int i;
1576
1577         //first, free up data allocated for old bitmaps
1578         free_bitmap_replacements();
1579
1580         change_filename_extension(ifile_name, level_name, ".POG" );
1581
1582         ifile = cfopen(ifile_name,"rb");
1583
1584         if (ifile) {
1585                 int id,version,n_bitmaps;
1586                 int bitmap_data_size;
1587                 ushort *indices;
1588
1589                 id = cfile_read_int(ifile);
1590                 version = cfile_read_int(ifile);
1591
1592                 if (id != MAKE_SIG('G','O','P','D') || version != 1) {
1593                         cfclose(ifile);
1594                         return;
1595                 }
1596
1597                 n_bitmaps = cfile_read_int(ifile);
1598
1599                 MALLOC( indices, ushort, n_bitmaps );
1600
1601                 for (i = 0; i < n_bitmaps; i++)
1602                         indices[i] = cfile_read_short(ifile);
1603
1604                 bitmap_data_size = cfilelength(ifile) - cftell(ifile) - sizeof(DiskBitmapHeader) * n_bitmaps;
1605                 MALLOC( Bitmap_replacement_data, ubyte, bitmap_data_size );
1606
1607                 for (i=0;i<n_bitmaps;i++) {
1608                         DiskBitmapHeader bmh;
1609                         grs_bitmap *bm = &GameBitmaps[indices[i]];
1610                         int width;
1611
1612                         DiskBitmapHeader_read(&bmh, ifile);
1613
1614                         width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
1615                         gr_set_bitmap_data(bm, NULL);   // free ogl texture
1616                         gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
1617                         bm->avg_color = bmh.avg_color;
1618                         bm->bm_data = (ubyte *) bmh.offset;
1619
1620                         gr_set_bitmap_flags(bm, bmh.flags & BM_FLAGS_TO_COPY);
1621
1622                         GameBitmapOffset[indices[i]] = 0; // don't try to read bitmap from current pigfile
1623                 }
1624
1625                 cfread(Bitmap_replacement_data,1,bitmap_data_size,ifile);
1626
1627                 for (i = 0; i < n_bitmaps; i++)
1628                 {
1629                         grs_bitmap *bm = &GameBitmaps[indices[i]];
1630                         gr_set_bitmap_data(bm, Bitmap_replacement_data + (int) bm->bm_data);
1631                 }
1632
1633                 d_free(indices);
1634
1635                 cfclose(ifile);
1636
1637                 last_palette_loaded_pig[0]= 0;  //force pig re-load
1638
1639                 texmerge_flush();       //for re-merging with new textures
1640         }
1641
1642         atexit(free_bitmap_replacements);
1643 }
1644
1645 /* calculate table to translate d1 bitmaps to current palette,
1646  * return -1 on error
1647  */
1648 int get_d1_colormap( ubyte *d1_palette, ubyte *colormap )
1649 {
1650         int freq[256];
1651         CFILE * palette_file = cfopen(D1_PALETTE, "rb");
1652         if (!palette_file || cfilelength(palette_file) != 9472)
1653                 return -1;
1654         cfread( d1_palette, 256, 3, palette_file);
1655         cfclose( palette_file );
1656         build_colormap_good( d1_palette, colormap, freq );
1657         // don't change transparencies:
1658         colormap[254] = 254;
1659         colormap[255] = 255;
1660         return 0;
1661 }
1662
1663 #define JUST_IN_CASE 132 /* is enough for d1 pc registered */
1664 void bitmap_read_d1( grs_bitmap *bitmap, /* read into this bitmap */
1665                      CFILE *d1_Piggy_fp, /* read from this file */
1666                      int bitmap_data_start, /* specific to file */
1667                      DiskBitmapHeader *bmh, /* header info for bitmap */
1668                      ubyte **next_bitmap, /* where to write it (if 0, use malloc) */
1669                      ubyte *d1_palette, /* what palette the bitmap has */
1670                      ubyte *colormap) /* how to translate bitmap's colors */
1671 {
1672         int zsize, pigsize = cfilelength(d1_Piggy_fp);
1673         ubyte *data;
1674         int width;
1675
1676         width = bmh->width + ((short) (bmh->wh_extra & 0x0f) << 8);
1677         gr_set_bitmap_data(bitmap, NULL);       // free ogl texture
1678         gr_init_bitmap(bitmap, 0, 0, 0, width, bmh->height + ((short) (bmh->wh_extra & 0xf0) << 4), width, NULL);
1679         bitmap->avg_color = bmh->avg_color;
1680         gr_set_bitmap_flags(bitmap, bmh->flags & BM_FLAGS_TO_COPY);
1681
1682         cfseek(d1_Piggy_fp, bitmap_data_start + bmh->offset, SEEK_SET);
1683         if (bmh->flags & BM_FLAG_RLE) {
1684                 zsize = cfile_read_int(d1_Piggy_fp);
1685                 cfseek(d1_Piggy_fp, -4, SEEK_CUR);
1686         } else
1687                 zsize = bitmap->bm_h * bitmap->bm_w;
1688
1689         if (next_bitmap) {
1690                 data = *next_bitmap;
1691                 *next_bitmap += zsize;
1692         } else {
1693                 data = d_malloc(zsize + JUST_IN_CASE);
1694         }
1695         if (!data) return;
1696
1697         cfread(data, 1, zsize, d1_Piggy_fp);
1698         gr_set_bitmap_data(bitmap, data);
1699         switch(pigsize) {
1700         case D1_MAC_PIGSIZE:
1701         case D1_MAC_SHARE_PIGSIZE:
1702                 if (bmh->flags & BM_FLAG_RLE)
1703                         rle_swap_0_255(bitmap);
1704                 else
1705                         swap_0_255(bitmap);
1706         }
1707         if (bmh->flags & BM_FLAG_RLE)
1708                 rle_remap(bitmap, colormap);
1709         else
1710                 gr_remap_bitmap_good(bitmap, d1_palette, TRANSPARENCY_COLOR, -1);
1711         if (bmh->flags & BM_FLAG_RLE) { // size of bitmap could have changed!
1712                 int new_size;
1713                 memcpy(&new_size, bitmap->bm_data, 4);
1714                 if (next_bitmap) {
1715                         *next_bitmap += new_size - zsize;
1716                 } else {
1717                         Assert( zsize + JUST_IN_CASE >= new_size );
1718                         bitmap->bm_data = d_realloc(bitmap->bm_data, new_size);
1719                         Assert(bitmap->bm_data);
1720                 }
1721         }
1722 }
1723
1724 #define D1_MAX_TEXTURES 800
1725 #define D1_MAX_TMAP_NUM 1630 // 1621 in descent.pig Mac registered
1726
1727 /* the inverse of the d2 Textures array, but for the descent 1 pigfile.
1728  * "Textures" looks up a d2 bitmap index given a d2 tmap_num.
1729  * "d1_tmap_nums" looks up a d1 tmap_num given a d1 bitmap. "-1" means "None".
1730  */
1731 short *d1_tmap_nums = NULL;
1732
1733 void free_d1_tmap_nums() {
1734         if (d1_tmap_nums) {
1735                 d_free(d1_tmap_nums);
1736                 d1_tmap_nums = NULL;
1737         }
1738 }
1739
1740 void bm_read_d1_tmap_nums(CFILE *d1pig)
1741 {
1742         int i, d1_index;
1743
1744         free_d1_tmap_nums();
1745         cfseek(d1pig, 8, SEEK_SET);
1746         MALLOC(d1_tmap_nums, short, D1_MAX_TMAP_NUM);
1747         for (i = 0; i < D1_MAX_TMAP_NUM; i++)
1748                 d1_tmap_nums[i] = -1;
1749         for (i = 0; i < D1_MAX_TEXTURES; i++) {
1750                 d1_index = cfile_read_short(d1pig);
1751                 Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
1752                 d1_tmap_nums[d1_index] = i;
1753         }
1754         atexit(free_d1_tmap_nums);
1755 }
1756
1757 void remove_char( char * s, char c )
1758 {
1759         char *p;
1760         p = strchr(s,c);
1761         if (p) *p = '\0';
1762 }
1763
1764 #define REMOVE_EOL(s)           remove_char((s),'\n')
1765 #define REMOVE_COMMENTS(s)      remove_char((s),';')
1766 #define REMOVE_DOTS(s)          remove_char((s),'.')
1767 char *space = { " \t" };
1768 char *equal_space = { " \t=" };
1769
1770 // this function is at the same position in the d1 shareware piggy loading 
1771 // algorithm as bm_load_sub in main/bmread.c
1772 int get_d1_bm_index(char *filename, CFILE *d1_pig) {
1773         int i, N_bitmaps;
1774         DiskBitmapHeader bmh;
1775         if (strchr (filename, '.'))
1776                 *strchr (filename, '.') = '\0'; // remove extension
1777         cfseek (d1_pig, 0, SEEK_SET);
1778         N_bitmaps = cfile_read_int (d1_pig);
1779         cfseek (d1_pig, 8, SEEK_SET);
1780         for (i = 1; i <= N_bitmaps; i++) {
1781                 DiskBitmapHeader_d1_read(&bmh, d1_pig);
1782                 if (!strnicmp(bmh.name, filename, 8))
1783                         return i;
1784         }
1785         return -1;
1786 }
1787
1788 // imitate the algorithm of bm_init_use_tbl in main/bmread.c
1789 void read_d1_tmap_nums_from_hog(CFILE *d1_pig)
1790 {
1791 #define LINEBUF_SIZE 600
1792         int reading_textures = 0;
1793         short texture_count = 0;
1794         char inputline[LINEBUF_SIZE];
1795         CFILE * bitmaps;
1796         int bitmaps_tbl_is_binary = 0;
1797         int i;
1798
1799         bitmaps = cfopen ("bitmaps.tbl", "rb");
1800         if (!bitmaps) {
1801                 bitmaps = cfopen ("bitmaps.bin", "rb");
1802                 bitmaps_tbl_is_binary = 1;
1803         }
1804
1805         if (!bitmaps) {
1806                 Warning ("Could not find bitmaps.* for reading d1 textures");
1807                 return;
1808         }
1809
1810         free_d1_tmap_nums();
1811         MALLOC(d1_tmap_nums, short, D1_MAX_TMAP_NUM);
1812         for (i = 0; i < D1_MAX_TMAP_NUM; i++)
1813                 d1_tmap_nums[i] = -1;
1814         atexit(free_d1_tmap_nums);
1815
1816         while (cfgets (inputline, LINEBUF_SIZE, bitmaps)) {
1817                 char *arg;
1818
1819                 if (bitmaps_tbl_is_binary)
1820                         decode_text_line((inputline));
1821                 else
1822                         while (inputline[(i = (int)strlen(inputline)) - 2] == '\\')
1823                                 cfgets(inputline+i-2,LINEBUF_SIZE-(i-2), bitmaps); // strip comments
1824                 REMOVE_EOL(inputline);
1825                 if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline);
1826                 if (strlen(inputline) == LINEBUF_SIZE-1) {
1827                         Warning("Possible line truncation in BITMAPS.TBL");
1828                         return;
1829                 }
1830                 arg = strtok( inputline, space );
1831                 if (arg && arg[0] == '@') {
1832                         arg++;
1833                         //Registered_only = 1;
1834                 }
1835
1836                 while (arg != NULL) {
1837                         if (*arg == '$')
1838                                 reading_textures = 0; // default
1839                         if (!strcmp(arg, "$TEXTURES")) // BM_TEXTURES
1840                                 reading_textures = 1;
1841                         else if (! stricmp(arg, "$ECLIP") // BM_ECLIP
1842                                    || ! stricmp(arg, "$WCLIP")) // BM_WCLIP
1843                                         texture_count++;
1844                         else // not a special token, must be a bitmap!
1845                                 if (reading_textures) {
1846                                         while (*arg == '\t' || *arg == ' ')
1847                                                 arg++;//remove unwanted blanks
1848                                         if (*arg == '\0')
1849                                                 break;
1850                                         if (d1_tmap_num_unique(texture_count)) {
1851                                                 int d1_index = get_d1_bm_index(arg, d1_pig);
1852                                                 if (d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM) {
1853                                                         d1_tmap_nums[d1_index] = texture_count;
1854                                                         //int d2_index = d2_index_for_d1_index(d1_index);
1855                                                 }
1856                                 }
1857                                 Assert (texture_count < D1_MAX_TEXTURES);
1858                                 texture_count++;
1859                         }
1860
1861                         arg = strtok (NULL, equal_space);
1862                 }
1863         }
1864         cfclose (bitmaps);
1865 }
1866
1867 /* If the given d1_index is the index of a bitmap we have to load
1868  * (because it is unique to descent 1), then returns the d2_index that
1869  * the given d1_index replaces.
1870  * Returns -1 if the given d1_index is not unique to descent 1.
1871  */
1872 short d2_index_for_d1_index(short d1_index)
1873 {
1874         Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
1875         if (! d1_tmap_nums || d1_tmap_nums[d1_index] == -1
1876             || ! d1_tmap_num_unique(d1_tmap_nums[d1_index]))
1877                 return -1;
1878
1879         return Textures[convert_d1_tmap_num(d1_tmap_nums[d1_index])].index;
1880 }
1881
1882 #define D1_BITMAPS_SIZE 300000
1883 void load_d1_bitmap_replacements()
1884 {
1885         CFILE * d1_Piggy_fp;
1886         DiskBitmapHeader bmh;
1887         int pig_data_start, bitmap_header_start, bitmap_data_start;
1888         int N_bitmaps;
1889         short d1_index, d2_index;
1890         ubyte* next_bitmap;
1891         ubyte colormap[256];
1892         ubyte d1_palette[256*3];
1893         char *p;
1894         int pigsize;
1895
1896         d1_Piggy_fp = cfopen( D1_PIGFILE, "rb" );
1897
1898 #define D1_PIG_LOAD_FAILED "Failed loading " D1_PIGFILE
1899         if (!d1_Piggy_fp) {
1900                 Warning(D1_PIG_LOAD_FAILED);
1901                 return;
1902         }
1903
1904         //first, free up data allocated for old bitmaps
1905         free_bitmap_replacements();
1906
1907         if (get_d1_colormap( d1_palette, colormap ) != 0)
1908                 Warning("Could not load descent 1 color palette");
1909
1910         pigsize = cfilelength(d1_Piggy_fp);
1911         switch (pigsize) {
1912         case D1_SHARE_BIG_PIGSIZE:
1913         case D1_SHARE_10_PIGSIZE:
1914         case D1_SHARE_PIGSIZE:
1915         case D1_10_BIG_PIGSIZE:
1916         case D1_10_PIGSIZE:
1917                 pig_data_start = 0;
1918                 // OK, now we need to read d1_tmap_nums by emulating d1's bm_init_use_tbl()
1919                 read_d1_tmap_nums_from_hog(d1_Piggy_fp);
1920                 break;
1921         default:
1922                 Warning("Unknown size for " D1_PIGFILE);
1923                 Int3();
1924                 // fall through
1925         case D1_PIGSIZE:
1926         case D1_OEM_PIGSIZE:
1927         case D1_MAC_PIGSIZE:
1928         case D1_MAC_SHARE_PIGSIZE:
1929                 pig_data_start = cfile_read_int(d1_Piggy_fp );
1930                 bm_read_d1_tmap_nums(d1_Piggy_fp); //was: bm_read_all_d1(fp);
1931                 //for (i = 0; i < 1800; i++) GameBitmapXlat[i] = cfile_read_short(d1_Piggy_fp);
1932                 break;
1933         }
1934
1935         cfseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
1936         N_bitmaps = cfile_read_int(d1_Piggy_fp);
1937         {
1938                 int N_sounds = cfile_read_int(d1_Piggy_fp);
1939                 int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
1940                         + N_sounds * sizeof(DiskSoundHeader);
1941                 bitmap_header_start = pig_data_start + 2 * sizeof(int);
1942                 bitmap_data_start = bitmap_header_start + header_size;
1943         }
1944
1945         MALLOC( Bitmap_replacement_data, ubyte, D1_BITMAPS_SIZE);
1946         if (!Bitmap_replacement_data) {
1947                 Warning(D1_PIG_LOAD_FAILED);
1948                 return;
1949         }
1950         atexit(free_bitmap_replacements);
1951
1952         next_bitmap = Bitmap_replacement_data;
1953
1954         for (d1_index = 1; d1_index <= N_bitmaps; d1_index++ ) {
1955                 d2_index = d2_index_for_d1_index(d1_index);
1956                 // only change bitmaps which are unique to d1
1957                 if (d2_index != -1) {
1958                         cfseek(d1_Piggy_fp, bitmap_header_start + (d1_index-1) * DISKBITMAPHEADER_D1_SIZE, SEEK_SET);
1959                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
1960
1961                         bitmap_read_d1( &GameBitmaps[d2_index], d1_Piggy_fp, bitmap_data_start, &bmh, &next_bitmap, d1_palette, colormap );
1962                         Assert(next_bitmap - Bitmap_replacement_data < D1_BITMAPS_SIZE);
1963                         GameBitmapOffset[d2_index] = 0; // don't try to read bitmap from current d2 pigfile
1964                         GameBitmapFlags[d2_index] = bmh.flags;
1965
1966                         if ( (p = strchr(AllBitmaps[d2_index].name, '#')) /* d2 BM is animated */
1967                              && !(bmh.dflags & DBM_FLAG_ABM) ) { /* d1 bitmap is not animated */
1968                                 int i, len = (int)(p - AllBitmaps[d2_index].name);
1969                                 for (i = 0; i < Num_bitmap_files; i++)
1970                                         if (i != d2_index && ! memcmp(AllBitmaps[d2_index].name, AllBitmaps[i].name, len))
1971                                         {
1972                                                 gr_set_bitmap_data(&GameBitmaps[i], NULL);      // free ogl texture
1973                                                 GameBitmaps[i] = GameBitmaps[d2_index];
1974                                                 GameBitmapOffset[i] = 0;
1975                                                 GameBitmapFlags[i] = bmh.flags;
1976                                         }
1977                         }
1978                 }
1979         }
1980
1981         cfclose(d1_Piggy_fp);
1982
1983         last_palette_loaded_pig[0]= 0;  //force pig re-load
1984
1985         texmerge_flush();       //for re-merging with new textures
1986 }
1987
1988
1989 extern int extra_bitmap_num;
1990
1991 /*
1992  * Find and load the named bitmap from descent.pig
1993  * similar to read_extra_bitmap_iff
1994  */
1995 bitmap_index read_extra_bitmap_d1_pig(char *name)
1996 {
1997         bitmap_index bitmap_num;
1998         grs_bitmap * new = &GameBitmaps[extra_bitmap_num];
1999
2000         bitmap_num.index = 0;
2001
2002         {
2003                 CFILE *d1_Piggy_fp;
2004                 DiskBitmapHeader bmh;
2005                 int pig_data_start, bitmap_header_start, bitmap_data_start;
2006                 int i, N_bitmaps;
2007                 ubyte colormap[256];
2008                 ubyte d1_palette[256*3];
2009                 int pigsize;
2010
2011                 d1_Piggy_fp = cfopen(D1_PIGFILE, "rb");
2012
2013                 if (!d1_Piggy_fp)
2014                 {
2015                         Warning(D1_PIG_LOAD_FAILED);
2016                         return bitmap_num;
2017                 }
2018
2019                 if (get_d1_colormap( d1_palette, colormap ) != 0)
2020                         Warning("Could not load descent 1 color palette");
2021
2022                 pigsize = cfilelength(d1_Piggy_fp);
2023                 switch (pigsize) {
2024                 case D1_SHARE_BIG_PIGSIZE:
2025                 case D1_SHARE_10_PIGSIZE:
2026                 case D1_SHARE_PIGSIZE:
2027                 case D1_10_BIG_PIGSIZE:
2028                 case D1_10_PIGSIZE:
2029                         pig_data_start = 0;
2030                         break;
2031                 default:
2032                         Warning("Unknown size for " D1_PIGFILE);
2033                         Int3();
2034                         // fall through
2035                 case D1_PIGSIZE:
2036                 case D1_OEM_PIGSIZE:
2037                 case D1_MAC_PIGSIZE:
2038                 case D1_MAC_SHARE_PIGSIZE:
2039                         pig_data_start = cfile_read_int(d1_Piggy_fp );
2040
2041                         break;
2042                 }
2043
2044                 cfseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
2045                 N_bitmaps = cfile_read_int(d1_Piggy_fp);
2046                 {
2047                         int N_sounds = cfile_read_int(d1_Piggy_fp);
2048                         int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
2049                                 + N_sounds * sizeof(DiskSoundHeader);
2050                         bitmap_header_start = pig_data_start + 2 * sizeof(int);
2051                         bitmap_data_start = bitmap_header_start + header_size;
2052                 }
2053
2054                 for (i = 1; i <= N_bitmaps; i++)
2055                 {
2056                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
2057                         if (!strnicmp(bmh.name, name, 8))
2058                                 break;
2059                 }
2060
2061                 if (strnicmp(bmh.name, name, 8))
2062                 {
2063                         con_printf(CON_DEBUG, "could not find bitmap %s\n", name);
2064                         return bitmap_num;
2065                 }
2066
2067                 bitmap_read_d1( new, d1_Piggy_fp, bitmap_data_start, &bmh, 0, d1_palette, colormap );
2068
2069                 cfclose(d1_Piggy_fp);
2070         }
2071
2072         new->avg_color = 0;     //compute_average_pixel(new);
2073
2074         bitmap_num.index = extra_bitmap_num;
2075
2076         GameBitmaps[extra_bitmap_num++] = *new;
2077
2078         return bitmap_num;
2079 }
2080
2081
2082 #ifndef FAST_FILE_IO
2083 /*
2084  * reads a bitmap_index structure from a CFILE
2085  */
2086 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
2087 {
2088         bi->index = cfile_read_short(fp);
2089 }
2090
2091 /*
2092  * reads n bitmap_index structs from a CFILE
2093  */
2094 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
2095 {
2096         int i;
2097
2098         for (i = 0; i < n; i++)
2099                 bi[i].index = cfile_read_short(fp);
2100         return i;
2101 }
2102 #endif // FAST_FILE_IO