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