amd64 fixes
[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         #ifdef MACINTOSH
620         char name[255];         // filename + path for the mac
621         #endif
622
623         piggy_close_file();             //close old pig if still open
624
625         //rename pigfile for shareware
626         if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(filename))
627                 filename = DEFAULT_PIGFILE_SHAREWARE;
628
629         #ifndef MACINTOSH
630                 Piggy_fp = cfopen( filename, "rb" );
631         #else
632                 sprintf(name, ":Data:%s", filename);
633                 Piggy_fp = cfopen( name, "rb" );
634
635                 #ifdef SHAREWARE        // if we are in the shareware version, we must have the pig by now.
636                         if (Piggy_fp == NULL)
637                         {
638                                 Error("Cannot load required file <%s>",name);
639                         }
640                 #endif  // end of if def shareware
641
642         #endif
643
644         if (!Piggy_fp) {
645                 #ifdef EDITOR
646                         return;         //if editor, ok to not have pig, because we'll build one
647                 #else
648                         Piggy_fp = copy_pigfile_from_cd(filename);
649                 #endif
650         }
651
652         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
653                 int pig_id,pig_version;
654
655                 pig_id = cfile_read_int(Piggy_fp);
656                 pig_version = cfile_read_int(Piggy_fp);
657                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
658                         cfclose(Piggy_fp);              //out of date pig
659                         Piggy_fp = NULL;                        //..so pretend it's not here
660                 }
661         }
662
663         if (!Piggy_fp) {
664
665                 #ifdef EDITOR
666                         return;         //if editor, ok to not have pig, because we'll build one
667                 #else
668                         Error("Cannot load required file <%s>",filename);
669                 #endif
670         }
671
672         strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
673
674         N_bitmaps = cfile_read_int(Piggy_fp);
675
676         header_size = N_bitmaps * sizeof(DiskBitmapHeader);
677
678         data_start = header_size + cftell(Piggy_fp);
679
680         data_size = cfilelength(Piggy_fp) - data_start;
681
682         Num_bitmap_files = 1;
683
684         for (i=0; i<N_bitmaps; i++ )
685     {
686                 int width;
687                 grs_bitmap *bm = &GameBitmaps[i + 1];
688                 
689                 DiskBitmapHeader_read(&bmh, Piggy_fp);
690                 memcpy( temp_name_read, bmh.name, 8 );
691                 temp_name_read[8] = 0;
692                 if ( bmh.dflags & DBM_FLAG_ABM )        
693                         sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & DBM_NUM_FRAMES );
694                 else
695                         strcpy( temp_name, temp_name_read );
696                 width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
697                 gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
698                 bm->bm_flags = BM_FLAG_PAGED_OUT;
699                 bm->avg_color = bmh.avg_color;
700
701                 GameBitmapFlags[i+1] = bmh.flags & BM_FLAGS_TO_COPY;
702
703                 GameBitmapOffset[i+1] = bmh.offset + data_start;
704                 Assert( (i+1) == Num_bitmap_files );
705                 piggy_register_bitmap(bm, temp_name, 1);
706         }
707
708 #ifdef EDITOR
709         Piggy_bitmap_cache_size = data_size + (data_size/10);   //extra mem for new bitmaps
710         Assert( Piggy_bitmap_cache_size > 0 );
711 #else
712         Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
713         #ifdef MACINTOSH
714         if (piggy_low_memory)
715                 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
716         #endif
717 #endif
718         BitmapBits = d_malloc( Piggy_bitmap_cache_size );
719         if ( BitmapBits == NULL )
720                 Error( "Not enough memory to load bitmaps\n" );
721         Piggy_bitmap_cache_data = BitmapBits;
722         Piggy_bitmap_cache_next = 0;
723
724         #if defined(MACINTOSH) && defined(SHAREWARE)
725 //      load_exit_models();
726         #endif
727
728         Pigfile_initialized=1;
729 }
730
731 #define FILENAME_LEN 13
732 #define MAX_BITMAPS_PER_BRUSH 30
733
734 extern int compute_average_pixel(grs_bitmap *new);
735 extern void gr_set_bitmap_data(grs_bitmap *bm, unsigned char *data);
736
737 ubyte *Bitmap_replacement_data = NULL;
738
739 //reads in a new pigfile (for new palette)
740 //returns the size of all the bitmap data
741 void piggy_new_pigfile(char *pigname)
742 {
743         int i;
744         char temp_name[16];
745         char temp_name_read[16];
746         DiskBitmapHeader bmh;
747         int header_size, N_bitmaps, data_size, data_start;
748         int must_rewrite_pig = 0;
749         #ifdef MACINTOSH
750         char name[255];
751         #endif
752
753         strlwr(pigname);
754
755         //rename pigfile for shareware
756         if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(pigname))
757                 pigname = DEFAULT_PIGFILE_SHAREWARE;
758
759         if (strnicmp(Current_pigfile, pigname, sizeof(Current_pigfile)) == 0 // correct pig already loaded
760             && !Bitmap_replacement_data) // no need to reload: no bitmaps were altered
761                 return;
762
763         if (!Pigfile_initialized) {                     //have we ever opened a pigfile?
764                 piggy_init_pigfile(pigname);            //..no, so do initialization stuff
765                 return;
766         }
767         else
768                 piggy_close_file();             //close old pig if still open
769
770         Piggy_bitmap_cache_next = 0;            //free up cache
771
772         strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
773
774         #ifndef MACINTOSH
775                 Piggy_fp = cfopen( pigname, "rb" );
776         #else
777                 sprintf(name, ":Data:%s", pigname);
778                 Piggy_fp = cfopen( name, "rb" );
779
780                 #ifdef SHAREWARE        // if we are in the shareware version, we must have the pig by now.
781                         if (Piggy_fp == NULL)
782                         {
783                                 Error("Cannot load required file <%s>",name);
784                         }
785                 #endif  // end of if def shareware
786         #endif
787
788         #ifndef EDITOR
789         if (!Piggy_fp)
790                 Piggy_fp = copy_pigfile_from_cd(pigname);
791         #endif
792
793         if (Piggy_fp) {  //make sure pig is valid type file & is up-to-date
794                 int pig_id,pig_version;
795
796                 pig_id = cfile_read_int(Piggy_fp);
797                 pig_version = cfile_read_int(Piggy_fp);
798                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
799                         cfclose(Piggy_fp);              //out of date pig
800                         Piggy_fp = NULL;                        //..so pretend it's not here
801                 }
802         }
803
804 #ifndef EDITOR
805         if (!Piggy_fp)
806                 Error("Cannot open correct version of <%s>", pigname);
807 #endif
808
809         if (Piggy_fp) {
810
811                 N_bitmaps = cfile_read_int(Piggy_fp);
812
813                 header_size = N_bitmaps * sizeof(DiskBitmapHeader);
814
815                 data_start = header_size + cftell(Piggy_fp);
816
817                 data_size = cfilelength(Piggy_fp) - data_start;
818
819                 for (i=1; i<=N_bitmaps; i++ )
820                 {
821                         grs_bitmap *bm = &GameBitmaps[i];
822                         int width;
823                         
824                         DiskBitmapHeader_read(&bmh, Piggy_fp);
825                         memcpy( temp_name_read, bmh.name, 8 );
826                         temp_name_read[8] = 0;
827         
828                         if ( bmh.dflags & DBM_FLAG_ABM )        
829                                 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & DBM_NUM_FRAMES );
830                         else
831                                 strcpy( temp_name, temp_name_read );
832         
833                         //Make sure name matches
834                         if (strcmp(temp_name,AllBitmaps[i].name)) {
835                                 //Int3();       //this pig is out of date.  Delete it
836                                 must_rewrite_pig=1;
837                         }
838         
839                         strcpy(AllBitmaps[i].name,temp_name);
840
841                         width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
842                         gr_set_bitmap_data(bm, NULL);   // free ogl texture
843                         gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
844                         bm->bm_flags = BM_FLAG_PAGED_OUT;
845                         bm->avg_color = bmh.avg_color;
846
847                         GameBitmapFlags[i] = bmh.flags & BM_FLAGS_TO_COPY;
848         
849                         GameBitmapOffset[i] = bmh.offset + data_start;
850                 }
851         }
852         else
853                 N_bitmaps = 0;          //no pigfile, so no bitmaps
854
855         #ifndef EDITOR
856
857         Assert(N_bitmaps == Num_bitmap_files-1);
858
859         #else
860
861         if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
862                 int size;
863
864                 //re-read the bitmaps that aren't in this pig
865
866                 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
867                         char *p;
868
869                         p = strchr(AllBitmaps[i].name,'#');
870
871                         if (p) {   // this is an ABM == animated bitmap
872                                 char abmname[FILENAME_LEN];
873                                 int fnum;
874                                 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
875                                 int iff_error;          //reference parm to avoid warning message
876                                 ubyte newpal[768];
877                                 char basename[FILENAME_LEN];
878                                 int nframes;
879                         
880                                 strcpy(basename,AllBitmaps[i].name);
881                                 basename[p-AllBitmaps[i].name] = 0;  //cut off "#nn" part
882                                 
883                                 sprintf( abmname, "%s.abm", basename );
884
885                                 iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
886
887                                 if (iff_error != IFF_NO_ERROR)  {
888                                         mprintf((1,"File %s - IFF error: %s",abmname,iff_errormsg(iff_error)));
889                                         Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
890                                 }
891                         
892                                 for (fnum=0;fnum<nframes; fnum++)       {
893                                         char tempname[20];
894                                         int SuperX;
895
896                                         sprintf( tempname, "%s#%d", basename, fnum );
897
898                                         //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
899                                         SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
900                                         //above makes assumption that supertransparent color is 254
901
902                                         if ( iff_has_transparency )
903                                                 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
904                                         else
905                                                 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
906
907                                         bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
908
909 #ifdef EDITOR
910                                         if ( FindArg("-macdata") )
911                                                 swap_0_255( bm[fnum] );
912 #endif
913                                         if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
914
915                                         if (bm[fnum]->bm_flags & BM_FLAG_RLE)
916                                                 size = *((int *) bm[fnum]->bm_data);
917                                         else
918                                                 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
919
920                                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
921                                         d_free(bm[fnum]->bm_data);
922                                         bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
923                                         Piggy_bitmap_cache_next += size;
924
925                                         GameBitmaps[i+fnum] = *bm[fnum];
926
927                                         // -- mprintf( (0, "U" ));
928                                         d_free( bm[fnum] );
929                                 }
930
931                                 i += nframes-1;         //filled in multiple bitmaps
932                         }
933                         else {          //this is a BBM
934
935                                 grs_bitmap * new;
936                                 ubyte newpal[256*3];
937                                 int iff_error;
938                                 char bbmname[FILENAME_LEN];
939                                 int SuperX;
940
941                                 MALLOC( new, grs_bitmap, 1 );
942
943                                 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
944                                 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
945
946                                 new->bm_handle=0;
947                                 if (iff_error != IFF_NO_ERROR)          {
948                                         mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)));
949                                         Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
950                                 }
951
952                                 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
953                                 //above makes assumption that supertransparent color is 254
954
955                                 if ( iff_has_transparency )
956                                         gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
957                                 else
958                                         gr_remap_bitmap_good( new, newpal, -1, SuperX );
959
960                                 new->avg_color = compute_average_pixel(new);
961
962 #ifdef EDITOR
963                                 if ( FindArg("-macdata") )
964                                         swap_0_255( new );
965 #endif
966                                 if ( !BigPig )  gr_bitmap_rle_compress( new );
967
968                                 if (new->bm_flags & BM_FLAG_RLE)
969                                         size = *((int *) new->bm_data);
970                                 else
971                                         size = new->bm_w * new->bm_h;
972
973                                 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size);
974                                 d_free(new->bm_data);
975                                 new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
976                                 Piggy_bitmap_cache_next += size;
977
978                                 GameBitmaps[i] = *new;
979         
980                                 d_free( new );
981
982                                 // -- mprintf( (0, "U" ));
983                         }
984                 }
985
986                 //@@Dont' do these things which are done when writing
987                 //@@for (i=0; i < Num_bitmap_files; i++ )       {
988                 //@@    bitmap_index bi;
989                 //@@    bi.index = i;
990                 //@@    PIGGY_PAGE_IN( bi );
991                 //@@}
992                 //@@
993                 //@@piggy_close_file();
994
995                 piggy_write_pigfile(pigname);
996
997                 Current_pigfile[0] = 0;                 //say no pig, to force reload
998
999                 piggy_new_pigfile(pigname);             //read in just-generated pig
1000
1001
1002         }
1003         #endif  //ifdef EDITOR
1004
1005 }
1006
1007 ubyte bogus_data[64*64];
1008 ubyte bogus_bitmap_initialized=0;
1009 digi_sound bogus_sound;
1010
1011 #define HAMFILE_ID              MAKE_SIG('!','M','A','H') //HAM!
1012 #define HAMFILE_VERSION 3
1013 //version 1 -> 2:  save marker_model_num
1014 //version 2 -> 3:  removed sound files
1015
1016 #define SNDFILE_ID              MAKE_SIG('D','N','S','D') //DSND
1017 #define SNDFILE_VERSION 1
1018
1019 int read_hamfile()
1020 {
1021         CFILE * ham_fp = NULL;
1022         int ham_id;
1023         int sound_offset = 0;
1024         #ifdef MACINTOSH
1025         char name[255];
1026         #endif
1027
1028         #ifndef MACINTOSH
1029         ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
1030         #else
1031         sprintf(name, ":Data:%s", DEFAULT_HAMFILE );
1032         ham_fp = cfopen( name, "rb" );
1033         #endif
1034
1035         if (ham_fp == NULL) {
1036                 Must_write_hamfile = 1;
1037                 return 0;
1038         }
1039
1040         //make sure ham is valid type file & is up-to-date
1041         ham_id = cfile_read_int(ham_fp);
1042         Piggy_hamfile_version = cfile_read_int(ham_fp);
1043         if (ham_id != HAMFILE_ID)
1044                 Error("Cannot open ham file %s\n", DEFAULT_HAMFILE);
1045 #if 0
1046         if (ham_id != HAMFILE_ID || Piggy_hamfile_version != HAMFILE_VERSION) {
1047                 Must_write_hamfile = 1;
1048                 cfclose(ham_fp);                                                //out of date ham
1049                 return 0;
1050         }
1051 #endif
1052
1053         if (Piggy_hamfile_version < 3) // hamfile contains sound info
1054                 sound_offset = cfile_read_int(ham_fp);
1055
1056         #if 1 //ndef EDITOR
1057         {
1058                 //int i;
1059
1060                 bm_read_all(ham_fp);
1061                 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1062                 // no swap here?
1063                 //for (i = 0; i < MAX_BITMAP_FILES; i++) {
1064                         //GameBitmapXlat[i] = INTEL_SHORT(GameBitmapXlat[i]);
1065                         //printf("GameBitmapXlat[%d] = %d\n", i, GameBitmapXlat[i]);
1066                 //}
1067         }
1068         #endif
1069
1070         if (Piggy_hamfile_version < 3) {
1071                 int N_sounds;
1072                 int sound_start;
1073                 int header_size;
1074                 int i;
1075                 DiskSoundHeader sndh;
1076                 digi_sound temp_sound;
1077                 char temp_name_read[16];
1078                 int sbytes = 0;
1079
1080                 cfseek(ham_fp, sound_offset, SEEK_SET);
1081                 N_sounds = cfile_read_int(ham_fp);
1082
1083                 sound_start = cftell(ham_fp);
1084
1085                 header_size = N_sounds * sizeof(DiskSoundHeader);
1086
1087                 //Read sounds
1088
1089                 for (i=0; i<N_sounds; i++ ) {
1090                         DiskSoundHeader_read(&sndh, ham_fp);
1091                         temp_sound.length = sndh.length;
1092                         temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1093                         SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1094                         memcpy( temp_name_read, sndh.name, 8 );
1095                         temp_name_read[8] = 0;
1096                         piggy_register_sound( &temp_sound, temp_name_read, 1 );
1097 #ifdef MACINTOSH
1098                         if (piggy_is_needed(i))
1099 #endif          // note link to if.
1100                                 sbytes += sndh.length;
1101                         //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1102                 }
1103
1104                 SoundBits = d_malloc( sbytes + 16 );
1105                 if ( SoundBits == NULL )
1106                         Error( "Not enough memory to load sounds\n" );
1107
1108                 mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1109
1110                 //      piggy_read_sounds(ham_fp);
1111
1112         }
1113
1114         cfclose(ham_fp);
1115
1116         return 1;
1117
1118 }
1119
1120 int read_sndfile()
1121 {
1122         CFILE * snd_fp = NULL;
1123         int snd_id,snd_version;
1124         int N_sounds;
1125         int sound_start;
1126         int header_size;
1127         int i,size, length;
1128         DiskSoundHeader sndh;
1129         digi_sound temp_sound;
1130         char temp_name_read[16];
1131         int sbytes = 0;
1132         #ifdef MACINTOSH
1133         char name[255];
1134         #endif
1135
1136         #ifndef MACINTOSH
1137         snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
1138         #else
1139         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1140         snd_fp = cfopen( name, "rb");
1141         #endif
1142         
1143         if (snd_fp == NULL)
1144                 return 0;
1145
1146         //make sure soundfile is valid type file & is up-to-date
1147         snd_id = cfile_read_int(snd_fp);
1148         snd_version = cfile_read_int(snd_fp);
1149         if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) {
1150                 cfclose(snd_fp);                                                //out of date sound file
1151                 return 0;
1152         }
1153
1154         N_sounds = cfile_read_int(snd_fp);
1155
1156         sound_start = cftell(snd_fp);
1157         size = cfilelength(snd_fp) - sound_start;
1158         length = size;
1159         mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
1160
1161         header_size = N_sounds*sizeof(DiskSoundHeader);
1162
1163         //Read sounds
1164
1165         for (i=0; i<N_sounds; i++ ) {
1166                 DiskSoundHeader_read(&sndh, snd_fp);
1167                 //size -= sizeof(DiskSoundHeader);
1168                 temp_sound.length = sndh.length;
1169                 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1170                 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1171                 memcpy( temp_name_read, sndh.name, 8 );
1172                 temp_name_read[8] = 0;
1173                 piggy_register_sound( &temp_sound, temp_name_read, 1 );
1174                 #ifdef MACINTOSH
1175                 if (piggy_is_needed(i))
1176                 #endif          // note link to if.
1177                 sbytes += sndh.length;
1178                 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1179         }
1180
1181         SoundBits = d_malloc( sbytes + 16 );
1182         if ( SoundBits == NULL )
1183                 Error( "Not enough memory to load sounds\n" );
1184
1185         mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1186
1187 //      piggy_read_sounds(snd_fp);
1188
1189         cfclose(snd_fp);
1190
1191         return 1;
1192 }
1193
1194 int piggy_init(void)
1195 {
1196         int ham_ok=0,snd_ok=0;
1197         int i;
1198
1199         hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
1200         hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
1201
1202         for (i=0; i<MAX_SOUND_FILES; i++ )      {
1203                 GameSounds[i].length = 0;
1204                 GameSounds[i].data = NULL;
1205                 SoundOffset[i] = 0;
1206         }
1207
1208         for (i=0; i<MAX_BITMAP_FILES; i++ )     
1209                 GameBitmapXlat[i] = i;
1210
1211         if ( !bogus_bitmap_initialized )        {
1212                 int i;
1213                 ubyte c;
1214
1215                 bogus_bitmap_initialized = 1;
1216                 c = gr_find_closest_color( 0, 0, 63 );
1217                 for (i=0; i<4096; i++ ) bogus_data[i] = c;
1218                 c = gr_find_closest_color( 63, 0, 0 );
1219                 // Make a big red X !
1220                 for (i=0; i<64; i++ )   {
1221                         bogus_data[i*64+i] = c;
1222                         bogus_data[i*64+(63-i)] = c;
1223                 }
1224                 gr_init_bitmap(&GameBitmaps[Num_bitmap_files], 0, 0, 0, 64, 64, 64, bogus_data);
1225                 piggy_register_bitmap(&GameBitmaps[Num_bitmap_files], "bogus", 1);
1226                 bogus_sound.length = 64*64;
1227                 bogus_sound.data = bogus_data;
1228                 GameBitmapOffset[0] = 0;
1229         }
1230
1231         if ( FindArg( "-bigpig" ))
1232                 BigPig = 1;
1233
1234         if ( FindArg( "-lowmem" ))
1235                 piggy_low_memory = 1;
1236
1237         if ( FindArg( "-nolowmem" ))
1238                 piggy_low_memory = 0;
1239
1240         if (piggy_low_memory)
1241                 digi_lomem = 1;
1242
1243                 gr_set_curfont( SMALL_FONT );
1244                 gr_set_fontcolor(gr_find_closest_color_current( 20, 20, 20 ),-1 );
1245                 gr_printf( 0x8000, grd_curcanv->cv_h-20, "%s...", TXT_LOADING_DATA );
1246
1247 #if 1 //def EDITOR //need for d1 mission briefings
1248         piggy_init_pigfile(DEFAULT_PIGFILE);
1249 #endif
1250
1251         snd_ok = ham_ok = read_hamfile();
1252
1253         if (Piggy_hamfile_version >= 3)
1254                 snd_ok = read_sndfile();
1255
1256         atexit(piggy_close);
1257
1258         mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1259         return (ham_ok && snd_ok);               //read ok
1260 }
1261
1262 int piggy_is_needed(int soundnum)
1263 {
1264         int i;
1265
1266         if ( !digi_lomem ) return 1;
1267
1268         for (i=0; i<MAX_SOUNDS; i++ )   {
1269                 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1270                         return 1;
1271         }
1272         return 0;
1273 }
1274
1275
1276 void piggy_read_sounds(void)
1277 {
1278         CFILE * fp = NULL;
1279         ubyte * ptr;
1280         int i, sbytes;
1281         #ifdef MACINTOSH
1282         char name[255];
1283         #endif
1284
1285         ptr = SoundBits;
1286         sbytes = 0;
1287
1288         #ifndef MACINTOSH
1289         fp = cfopen( DEFAULT_SNDFILE, "rb" );
1290         #else
1291         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1292         fp = cfopen( name, "rb");
1293         #endif
1294
1295         if (fp == NULL)
1296                 return;
1297
1298         for (i=0; i<Num_sound_files; i++ )      {
1299                 digi_sound *snd = &GameSounds[i];
1300
1301                 if ( SoundOffset[i] > 0 )       {
1302                         if ( piggy_is_needed(i) )       {
1303                                 cfseek( fp, SoundOffset[i], SEEK_SET );
1304
1305                                 // Read in the sound data!!!
1306                                 snd->data = ptr;
1307                                 ptr += snd->length;
1308                                 sbytes += snd->length;
1309                                 cfread( snd->data, snd->length, 1, fp );
1310                         }
1311                         else
1312                                 snd->data = (ubyte *) -1;
1313                 }
1314         }
1315
1316         cfclose(fp);
1317
1318         mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1319
1320 }
1321
1322
1323 extern int descent_critical_error;
1324 extern unsigned descent_critical_deverror;
1325 extern unsigned descent_critical_errcode;
1326
1327 char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \
1328 "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \
1329 "Read fault", "General Failure" };
1330
1331 void piggy_critical_error()
1332 {
1333         grs_canvas * save_canv;
1334         grs_font * save_font;
1335         int i;
1336         save_canv = grd_curcanv;
1337         save_font = grd_curcanv->cv_font;
1338         gr_palette_load( gr_palette );
1339         i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A'  );
1340         if ( i == 1 )
1341                 exit(1);
1342         gr_set_current_canvas(save_canv);
1343         grd_curcanv->cv_font = save_font;
1344 }
1345
1346 extern void gr_set_bitmap_flags(grs_bitmap *pbm, int flags);
1347
1348 void piggy_bitmap_page_in( bitmap_index bitmap )
1349 {
1350         grs_bitmap * bmp;
1351         int i,org_i,temp;
1352
1353         org_i = 0;
1354
1355         i = bitmap.index;
1356         Assert( i >= 0 );
1357         Assert( i < MAX_BITMAP_FILES );
1358         Assert( i < Num_bitmap_files );
1359         Assert( Piggy_bitmap_cache_size > 0 );
1360
1361         if ( i < 1 ) return;
1362         if ( i >= MAX_BITMAP_FILES ) return;
1363         if ( i >= Num_bitmap_files ) return;
1364
1365         if ( GameBitmapOffset[i] == 0 ) return;         // A read-from-disk bitmap!!!
1366
1367         if ( piggy_low_memory ) {
1368                 org_i = i;
1369                 i = GameBitmapXlat[i];          // Xlat for low-memory settings!
1370         }
1371
1372         bmp = &GameBitmaps[i];
1373
1374         if ( bmp->bm_flags & BM_FLAG_PAGED_OUT )        {
1375                 stop_time();
1376
1377         ReDoIt:
1378                 descent_critical_error = 0;
1379                 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1380                 if ( descent_critical_error )   {
1381                         piggy_critical_error();
1382                         goto ReDoIt;
1383                 }
1384
1385                 gr_set_bitmap_flags(bmp, GameBitmapFlags[i]);
1386
1387                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1388                         int zsize = 0, pigsize = cfilelength(Piggy_fp);
1389                         descent_critical_error = 0;
1390                         zsize = cfile_read_int(Piggy_fp);
1391                         if ( descent_critical_error )   {
1392                                 piggy_critical_error();
1393                                 goto ReDoIt;
1394                         }
1395
1396                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1397                         //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
1398                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1399                                 Int3();
1400                                 piggy_bitmap_page_out_all();
1401                                 goto ReDoIt;
1402                         }
1403                         descent_critical_error = 0;
1404                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next+4], 1, zsize-4, Piggy_fp );
1405                         if ( descent_critical_error )   {
1406                                 piggy_critical_error();
1407                                 goto ReDoIt;
1408                         }
1409                         *((int *) (Piggy_bitmap_cache_data + Piggy_bitmap_cache_next)) = INTEL_INT(zsize);
1410                         gr_set_bitmap_data(bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
1411
1412 #ifndef MACDATA
1413                         switch (pigsize) {
1414                         default:
1415                                 if (!FindArg("-macdata"))
1416                                         break;
1417                                 // otherwise, fall through...
1418                         case MAC_ALIEN1_PIGSIZE:
1419                         case MAC_ALIEN2_PIGSIZE:
1420                         case MAC_FIRE_PIGSIZE:
1421                         case MAC_GROUPA_PIGSIZE:
1422                         case MAC_ICE_PIGSIZE:
1423                         case MAC_WATER_PIGSIZE:
1424                                 rle_swap_0_255( bmp );
1425                                 memcpy(&zsize, bmp->bm_data, 4);
1426                                 break;
1427                         }
1428 #endif
1429
1430                         Piggy_bitmap_cache_next += zsize;
1431                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1432                                 Int3();
1433                                 piggy_bitmap_page_out_all();
1434                                 goto ReDoIt;
1435                         }
1436
1437                 } else {
1438                         int pigsize = cfilelength(Piggy_fp);
1439                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1440                         Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
1441                         if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1442                                 piggy_bitmap_page_out_all();
1443                                 goto ReDoIt;
1444                         }
1445                         descent_critical_error = 0;
1446                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1447                         if ( descent_critical_error )   {
1448                                 piggy_critical_error();
1449                                 goto ReDoIt;
1450                         }
1451                         gr_set_bitmap_data(bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
1452                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1453
1454 #ifndef MACDATA
1455                         switch (pigsize) {
1456                         default:
1457                                 if (!FindArg("-macdata"))
1458                                         break;
1459                                 // otherwise, fall through...
1460                         case MAC_ALIEN1_PIGSIZE:
1461                         case MAC_ALIEN2_PIGSIZE:
1462                         case MAC_FIRE_PIGSIZE:
1463                         case MAC_GROUPA_PIGSIZE:
1464                         case MAC_ICE_PIGSIZE:
1465                         case MAC_WATER_PIGSIZE:
1466                                 swap_0_255( bmp );
1467                                 break;
1468                         }
1469 #endif
1470                 }
1471
1472                 //@@if ( bmp->bm_selector ) {
1473                 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1474                 //@@    if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1475                 //@@            Error( "Error modifying selector base in piggy.c\n" );
1476                 //@@#endif
1477                 //@@}
1478
1479                 start_time();
1480         }
1481
1482         if ( piggy_low_memory ) {
1483                 if ( org_i != i )
1484                         GameBitmaps[org_i] = GameBitmaps[i];
1485         }
1486
1487 //@@Removed from John's code:
1488 //@@#ifndef WINDOWS
1489 //@@    if ( bmp->bm_selector ) {
1490 //@@            if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1491 //@@                    Error( "Error modifying selector base in piggy.c\n" );
1492 //@@    }
1493 //@@#endif
1494
1495 }
1496
1497 void piggy_bitmap_page_out_all()
1498 {
1499         int i;
1500         
1501         Piggy_bitmap_cache_next = 0;
1502
1503         piggy_page_flushed++;
1504
1505         texmerge_flush();
1506         rle_cache_flush();
1507
1508         for (i=0; i<Num_bitmap_files; i++ )             {
1509                 if ( GameBitmapOffset[i] > 0 )  {       // Don't page out bitmaps read from disk!!!
1510                         GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1511                         gr_set_bitmap_data(&GameBitmaps[i], NULL);
1512                 }
1513         }
1514
1515         mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1516 }
1517
1518 void piggy_load_level_data()
1519 {
1520         piggy_bitmap_page_out_all();
1521         paging_touch_all();
1522 }
1523
1524 #ifdef EDITOR
1525
1526 void piggy_write_pigfile(char *filename)
1527 {
1528         FILE *pig_fp;
1529         int bitmap_data_start, data_offset;
1530         DiskBitmapHeader bmh;
1531         int org_offset;
1532         char subst_name[32];
1533         int i;
1534         FILE *fp1,*fp2;
1535         char tname[FILENAME_LEN];
1536
1537         // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1538         for (i=0; i < Num_bitmap_files; i++ )   {
1539                 bitmap_index bi;
1540                 bi.index = i;
1541                 PIGGY_PAGE_IN( bi );
1542         }
1543         // -- mprintf( (0, "\n" ));
1544
1545         piggy_close_file();
1546
1547         // -- mprintf( (0, "Creating %s...",filename ));
1548
1549         pig_fp = fopen( filename, "wb" );       //open PIG file
1550         Assert( pig_fp!=NULL );
1551
1552         write_int(PIGFILE_ID,pig_fp);
1553         write_int(PIGFILE_VERSION,pig_fp);
1554
1555         Num_bitmap_files--;
1556         fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1557         Num_bitmap_files++;
1558
1559         bitmap_data_start = ftell(pig_fp);
1560         bitmap_data_start += (Num_bitmap_files - 1) * sizeof(DiskBitmapHeader);
1561         data_offset = bitmap_data_start;
1562
1563         change_filename_extension(tname,filename,"lst");
1564         fp1 = fopen( tname, "wt" );
1565         change_filename_extension(tname,filename,"all");
1566         fp2 = fopen( tname, "wt" );
1567
1568         for (i=1; i < Num_bitmap_files; i++ )   {
1569                 int *size;
1570                 grs_bitmap *bmp;
1571
1572                 {               
1573                         char * p, *p1;
1574                         p = strchr(AllBitmaps[i].name, '#');
1575                         if (p) {   // this is an ABM == animated bitmap
1576                                 int n;
1577                                 p1 = p; p1++; 
1578                                 n = atoi(p1);
1579                                 *p = 0;
1580                                 if (fp2 && n==0)
1581                                         fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1582                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1583                                 Assert( n <= DBM_NUM_FRAMES );
1584                                 bmh.dflags = DBM_FLAG_ABM + n;
1585                                 *p = '#';
1586                         } else {
1587                                 if (fp2)
1588                                         fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1589                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1590                                 bmh.dflags = 0;
1591                         }
1592                 }
1593                 bmp = &GameBitmaps[i];
1594
1595                 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1596
1597                 if (fp1)
1598                         fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1599                 org_offset = ftell(pig_fp);
1600                 bmh.offset = data_offset - bitmap_data_start;
1601                 fseek( pig_fp, data_offset, SEEK_SET );
1602
1603                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1604                         size = (int *)bmp->bm_data;
1605                         fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1606                         data_offset += *size;
1607                         if (fp1)
1608                                 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1609                 } else {
1610                         fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1611                         data_offset += bmp->bm_rowsize * bmp->bm_h;
1612                         if (fp1)
1613                                 fprintf( fp1, ".\n" );
1614                 }
1615                 fseek( pig_fp, org_offset, SEEK_SET );
1616                 Assert( GameBitmaps[i].bm_w < 4096 );
1617                 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1618                 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1619                 Assert( GameBitmaps[i].bm_h < 4096 );
1620                 bmh.height = GameBitmaps[i].bm_h;
1621                 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1622                 bmh.flags = GameBitmaps[i].bm_flags;
1623                 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name ))    {
1624                         bitmap_index other_bitmap;
1625                         other_bitmap = piggy_find_bitmap( subst_name );
1626                         GameBitmapXlat[i] = other_bitmap.index;
1627                         bmh.flags |= BM_FLAG_PAGED_OUT;
1628                         //mprintf(( 0, "Skipping bitmap %d\n", i ));
1629                         //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1630                 } else  {
1631                         bmh.flags &= ~BM_FLAG_PAGED_OUT;
1632                 }
1633                 bmh.avg_color=GameBitmaps[i].avg_color;
1634                 fwrite(&bmh, sizeof(DiskBitmapHeader), 1, pig_fp);  // Mark as a bitmap
1635         }
1636
1637         fclose(pig_fp);
1638
1639         mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1640         fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1641
1642         fclose(fp1);
1643         fclose(fp2);
1644
1645 }
1646
1647 static void write_int(int i,FILE *file)
1648 {
1649         if (fwrite( &i, sizeof(i), 1, file) != 1)
1650                 Error( "Error reading int in gamesave.c" );
1651
1652 }
1653
1654 void piggy_dump_all()
1655 {
1656         int i, xlat_offset;
1657         FILE * ham_fp;
1658         int org_offset,data_offset=0;
1659         DiskSoundHeader sndh;
1660         int sound_data_start=0;
1661         FILE *fp1,*fp2;
1662
1663         #ifdef NO_DUMP_SOUNDS
1664         Num_sound_files = 0;
1665         Num_sound_files_new = 0;
1666         #endif
1667
1668         if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1669                 return;
1670
1671         fp1 = fopen( "ham.lst", "wt" );
1672         fp2 = fopen( "ham.all", "wt" );
1673
1674         if (Must_write_hamfile || Num_bitmap_files_new) {
1675
1676                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1677         
1678                 ham_fp = fopen( DEFAULT_HAMFILE, "wb" );                       //open HAM file
1679                 Assert( ham_fp!=NULL );
1680         
1681                 write_int(HAMFILE_ID,ham_fp);
1682                 write_int(HAMFILE_VERSION,ham_fp);
1683         
1684                 bm_write_all(ham_fp);
1685                 xlat_offset = ftell(ham_fp);
1686                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1687                 //Dump bitmaps
1688         
1689                 if (Num_bitmap_files_new)
1690                         piggy_write_pigfile(DEFAULT_PIGFILE);
1691         
1692                 //free up memeory used by new bitmaps
1693                 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1694                         d_free(GameBitmaps[i].bm_data);
1695         
1696                 //next thing must be done after pig written
1697                 fseek( ham_fp, xlat_offset, SEEK_SET );
1698                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1699         
1700                 fclose(ham_fp);
1701                 mprintf( (0, "\n" ));
1702         }
1703         
1704         if (Num_sound_files_new) {
1705
1706                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1707                 // Now dump sound file
1708                 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1709                 Assert( ham_fp!=NULL );
1710         
1711                 write_int(SNDFILE_ID,ham_fp);
1712                 write_int(SNDFILE_VERSION,ham_fp);
1713
1714                 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1715         
1716                 mprintf( (0, "\nDumping sounds..." ));
1717         
1718                 sound_data_start = ftell(ham_fp);
1719                 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1720                 data_offset = sound_data_start;
1721         
1722                 for (i=0; i < Num_sound_files; i++ )    {
1723                         digi_sound *snd;
1724         
1725                         snd = &GameSounds[i];
1726                         strcpy( sndh.name, AllSounds[i].name );
1727                         sndh.length = GameSounds[i].length;
1728                         sndh.offset = data_offset - sound_data_start;
1729         
1730                         org_offset = ftell(ham_fp);
1731                         fseek( ham_fp, data_offset, SEEK_SET );
1732         
1733                         sndh.data_length = GameSounds[i].length;
1734                         fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1735                         data_offset += snd->length;
1736                         fseek( ham_fp, org_offset, SEEK_SET );
1737                         fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp );                    // Mark as a bitmap
1738         
1739                         fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1740                         fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1741                 }
1742
1743                 fclose(ham_fp);
1744                 mprintf( (0, "\n" ));
1745         }
1746
1747         fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1748         mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1749         fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1750
1751         fclose(fp1);
1752         fclose(fp2);
1753
1754         // Never allow the game to run after building ham.
1755         exit(0);
1756 }
1757
1758 #endif
1759
1760 void piggy_close()
1761 {
1762         piggy_close_file();
1763
1764         if (BitmapBits)
1765                 d_free(BitmapBits);
1766
1767         if ( SoundBits )
1768                 d_free( SoundBits );
1769
1770         hashtable_free( &AllBitmapsNames );
1771         hashtable_free( &AllDigiSndNames );
1772
1773 }
1774
1775 int piggy_does_bitmap_exist_slow( char * name )
1776 {
1777         int i;
1778
1779         for (i=0; i<Num_bitmap_files; i++ )     {
1780                 if ( !strcmp( AllBitmaps[i].name, name) )
1781                         return 1;
1782         }
1783         return 0;
1784 }
1785
1786
1787 #define NUM_GAUGE_BITMAPS 23
1788 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1789         "gauge01", "gauge01b",
1790         "gauge02", "gauge02b",
1791         "gauge06", "gauge06b",
1792         "targ01", "targ01b",
1793         "targ02", "targ02b", 
1794         "targ03", "targ03b",
1795         "targ04", "targ04b",
1796         "targ05", "targ05b",
1797         "targ06", "targ06b",
1798         "gauge18", "gauge18b",
1799         "gauss1", "helix1",
1800         "phoenix1"
1801 };
1802
1803
1804 int piggy_is_gauge_bitmap( char * base_name )
1805 {
1806         int i;
1807         for (i=0; i<NUM_GAUGE_BITMAPS; i++ )    {
1808                 if ( !stricmp( base_name, gauge_bitmap_names[i] ))      
1809                         return 1;
1810         }
1811
1812         return 0;       
1813 }
1814
1815 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1816 {
1817         int frame;
1818         char * p;
1819         char base_name[ 16 ];
1820         
1821         strcpy( subst_name, name );
1822         p = strchr( subst_name, '#' );
1823         if ( p )        {
1824                 frame = atoi( &p[1] );
1825                 *p = 0;
1826                 strcpy( base_name, subst_name );
1827                 if ( !piggy_is_gauge_bitmap( base_name ))       {
1828                         sprintf( subst_name, "%s#%d", base_name, frame+1 );
1829                         if ( piggy_does_bitmap_exist_slow( subst_name )  )      {
1830                                 if ( frame & 1 ) {
1831                                         sprintf( subst_name, "%s#%d", base_name, frame-1 );
1832                                         return 1;
1833                                 }
1834                         }
1835                 }
1836         }
1837         strcpy( subst_name, name );
1838         return 0;
1839 }
1840
1841
1842
1843 /*
1844  * Functions for loading replacement textures
1845  *  1) From .pog files
1846  *  2) From descent.pig (for loading d1 levels)
1847  */
1848
1849 extern char last_palette_loaded_pig[];
1850
1851 void free_bitmap_replacements()
1852 {
1853         if (Bitmap_replacement_data) {
1854                 d_free(Bitmap_replacement_data);
1855                 Bitmap_replacement_data = NULL;
1856         }
1857 }
1858
1859 void load_bitmap_replacements(char *level_name)
1860 {
1861         char ifile_name[FILENAME_LEN];
1862         CFILE *ifile;
1863         int i;
1864
1865         //first, free up data allocated for old bitmaps
1866         free_bitmap_replacements();
1867
1868         change_filename_extension(ifile_name, level_name, ".POG" );
1869
1870         ifile = cfopen(ifile_name,"rb");
1871
1872         if (ifile) {
1873                 int id,version,n_bitmaps;
1874                 int bitmap_data_size;
1875                 ushort *indices;
1876
1877                 id = cfile_read_int(ifile);
1878                 version = cfile_read_int(ifile);
1879
1880                 if (id != MAKE_SIG('G','O','P','D') || version != 1) {
1881                         cfclose(ifile);
1882                         return;
1883                 }
1884
1885                 n_bitmaps = cfile_read_int(ifile);
1886
1887                 MALLOC( indices, ushort, n_bitmaps );
1888
1889                 for (i = 0; i < n_bitmaps; i++)
1890                         indices[i] = cfile_read_short(ifile);
1891
1892                 bitmap_data_size = cfilelength(ifile) - cftell(ifile) - sizeof(DiskBitmapHeader) * n_bitmaps;
1893                 MALLOC( Bitmap_replacement_data, ubyte, bitmap_data_size );
1894
1895                 for (i=0;i<n_bitmaps;i++) {
1896                         DiskBitmapHeader bmh;
1897                         grs_bitmap *bm = &GameBitmaps[indices[i]];
1898                         int width;
1899
1900                         DiskBitmapHeader_read(&bmh, ifile);
1901
1902                         width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
1903                         gr_set_bitmap_data(bm, NULL);   // free ogl texture
1904                         gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
1905                         bm->avg_color = bmh.avg_color;
1906                         bm->bm_data = (ubyte *) bmh.offset;
1907
1908                         gr_set_bitmap_flags(bm, bmh.flags & BM_FLAGS_TO_COPY);
1909
1910                         GameBitmapOffset[indices[i]] = 0; // don't try to read bitmap from current pigfile
1911                 }
1912
1913                 cfread(Bitmap_replacement_data,1,bitmap_data_size,ifile);
1914
1915                 for (i = 0; i < n_bitmaps; i++)
1916                 {
1917                         grs_bitmap *bm = &GameBitmaps[indices[i]];
1918                         gr_set_bitmap_data(bm, Bitmap_replacement_data + (int) bm->bm_data);
1919                 }
1920
1921                 d_free(indices);
1922
1923                 cfclose(ifile);
1924
1925                 last_palette_loaded_pig[0]= 0;  //force pig re-load
1926
1927                 texmerge_flush();       //for re-merging with new textures
1928         }
1929
1930         atexit(free_bitmap_replacements);
1931 }
1932
1933 /* calculate table to translate d1 bitmaps to current palette,
1934  * return -1 on error
1935  */
1936 int get_d1_colormap( ubyte *d1_palette, ubyte *colormap )
1937 {
1938         int freq[256];
1939         CFILE * palette_file = cfopen(D1_PALETTE, "rb");
1940         if (!palette_file || cfilelength(palette_file) != 9472)
1941                 return -1;
1942         cfread( d1_palette, 256, 3, palette_file);
1943         cfclose( palette_file );
1944         build_colormap_good( d1_palette, colormap, freq );
1945         // don't change transparencies:
1946         colormap[254] = 254;
1947         colormap[255] = 255;
1948         return 0;
1949 }
1950
1951 #define JUST_IN_CASE 132 /* is enough for d1 pc registered */
1952 void bitmap_read_d1( grs_bitmap *bitmap, /* read into this bitmap */
1953                      CFILE *d1_Piggy_fp, /* read from this file */
1954                      int bitmap_data_start, /* specific to file */
1955                      DiskBitmapHeader *bmh, /* header info for bitmap */
1956                      ubyte **next_bitmap, /* where to write it (if 0, use malloc) */
1957                      ubyte *d1_palette, /* what palette the bitmap has */
1958                      ubyte *colormap) /* how to translate bitmap's colors */
1959 {
1960         int zsize, pigsize = cfilelength(d1_Piggy_fp);
1961         ubyte *data;
1962         int width;
1963
1964         width = bmh->width + ((short) (bmh->wh_extra & 0x0f) << 8);
1965         gr_set_bitmap_data(bitmap, NULL);       // free ogl texture
1966         gr_init_bitmap(bitmap, 0, 0, 0, width, bmh->height + ((short) (bmh->wh_extra & 0xf0) << 4), width, NULL);
1967         bitmap->avg_color = bmh->avg_color;
1968         gr_set_bitmap_flags(bitmap, bmh->flags & BM_FLAGS_TO_COPY);
1969
1970         cfseek(d1_Piggy_fp, bitmap_data_start + bmh->offset, SEEK_SET);
1971         if (bmh->flags & BM_FLAG_RLE) {
1972                 zsize = cfile_read_int(d1_Piggy_fp);
1973                 cfseek(d1_Piggy_fp, -4, SEEK_CUR);
1974         } else
1975                 zsize = bitmap->bm_h * bitmap->bm_w;
1976
1977         if (next_bitmap) {
1978                 data = *next_bitmap;
1979                 *next_bitmap += zsize;
1980         } else {
1981                 data = d_malloc(zsize + JUST_IN_CASE);
1982         }
1983         if (!data) return;
1984
1985         cfread(data, 1, zsize, d1_Piggy_fp);
1986         gr_set_bitmap_data(bitmap, data);
1987         switch(pigsize) {
1988         case D1_MAC_PIGSIZE:
1989         case D1_MAC_SHARE_PIGSIZE:
1990                 if (bmh->flags & BM_FLAG_RLE)
1991                         rle_swap_0_255(bitmap);
1992                 else
1993                         swap_0_255(bitmap);
1994         }
1995         if (bmh->flags & BM_FLAG_RLE)
1996                 rle_remap(bitmap, colormap);
1997         else
1998                 gr_remap_bitmap_good(bitmap, d1_palette, TRANSPARENCY_COLOR, -1);
1999         if (bmh->flags & BM_FLAG_RLE) { // size of bitmap could have changed!
2000                 int new_size;
2001                 memcpy(&new_size, bitmap->bm_data, 4);
2002                 if (next_bitmap) {
2003                         *next_bitmap += new_size - zsize;
2004                 } else {
2005                         Assert( zsize + JUST_IN_CASE >= new_size );
2006                         bitmap->bm_data = d_realloc(bitmap->bm_data, new_size);
2007                         Assert(bitmap->bm_data);
2008                 }
2009         }
2010 }
2011
2012 #define D1_MAX_TEXTURES 800
2013 #define D1_MAX_TMAP_NUM 1630 // 1621 in descent.pig Mac registered
2014
2015 /* the inverse of the d2 Textures array, but for the descent 1 pigfile.
2016  * "Textures" looks up a d2 bitmap index given a d2 tmap_num.
2017  * "d1_tmap_nums" looks up a d1 tmap_num given a d1 bitmap. "-1" means "None".
2018  */
2019 short *d1_tmap_nums = NULL;
2020
2021 void free_d1_tmap_nums() {
2022         if (d1_tmap_nums) {
2023                 d_free(d1_tmap_nums);
2024                 d1_tmap_nums = NULL;
2025         }
2026 }
2027
2028 void bm_read_d1_tmap_nums(CFILE *d1pig)
2029 {
2030         int i, d1_index;
2031
2032         free_d1_tmap_nums();
2033         cfseek(d1pig, 8, SEEK_SET);
2034         MALLOC(d1_tmap_nums, short, D1_MAX_TMAP_NUM);
2035         for (i = 0; i < D1_MAX_TMAP_NUM; i++)
2036                 d1_tmap_nums[i] = -1;
2037         for (i = 0; i < D1_MAX_TEXTURES; i++) {
2038                 d1_index = cfile_read_short(d1pig);
2039                 Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
2040                 d1_tmap_nums[d1_index] = i;
2041         }
2042         atexit(free_d1_tmap_nums);
2043 }
2044
2045 void remove_char( char * s, char c )
2046 {
2047         char *p;
2048         p = strchr(s,c);
2049         if (p) *p = '\0';
2050 }
2051
2052 #define REMOVE_EOL(s)           remove_char((s),'\n')
2053 #define REMOVE_COMMENTS(s)      remove_char((s),';')
2054 #define REMOVE_DOTS(s)          remove_char((s),'.')
2055 char *space = { " \t" };
2056 char *equal_space = { " \t=" };
2057
2058 // this function is at the same position in the d1 shareware piggy loading 
2059 // algorithm as bm_load_sub in main/bmread.c
2060 int get_d1_bm_index(char *filename, CFILE *d1_pig) {
2061         int i, N_bitmaps;
2062         DiskBitmapHeader bmh;
2063         if (strchr (filename, '.'))
2064                 *strchr (filename, '.') = '\0'; // remove extension
2065         cfseek (d1_pig, 0, SEEK_SET);
2066         N_bitmaps = cfile_read_int (d1_pig);
2067         cfseek (d1_pig, 8, SEEK_SET);
2068         for (i = 1; i <= N_bitmaps; i++) {
2069                 DiskBitmapHeader_d1_read(&bmh, d1_pig);
2070                 if (!strnicmp(bmh.name, filename, 8))
2071                         return i;
2072         }
2073         return -1;
2074 }
2075
2076 // imitate the algorithm of bm_init_use_tbl in main/bmread.c
2077 void read_d1_tmap_nums_from_hog(CFILE *d1_pig)
2078 {
2079 #define LINEBUF_SIZE 600
2080         int reading_textures = 0;
2081         short texture_count = 0;
2082         char inputline[LINEBUF_SIZE];
2083         CFILE * bitmaps;
2084         int bitmaps_tbl_is_binary = 0;
2085         int i;
2086
2087         bitmaps = cfopen ("bitmaps.tbl", "rb");
2088         if (!bitmaps) {
2089                 bitmaps = cfopen ("bitmaps.bin", "rb");
2090                 bitmaps_tbl_is_binary = 1;
2091         }
2092
2093         if (!bitmaps) {
2094                 Warning ("Could not find bitmaps.* for reading d1 textures");
2095                 return;
2096         }
2097
2098         free_d1_tmap_nums();
2099         MALLOC(d1_tmap_nums, short, D1_MAX_TMAP_NUM);
2100         for (i = 0; i < D1_MAX_TMAP_NUM; i++)
2101                 d1_tmap_nums[i] = -1;
2102         atexit(free_d1_tmap_nums);
2103
2104         while (cfgets (inputline, LINEBUF_SIZE, bitmaps)) {
2105                 char *arg;
2106
2107                 if (bitmaps_tbl_is_binary)
2108                         decode_text_line((inputline));
2109                 else
2110                         while (inputline[(i=strlen(inputline))-2]=='\\')
2111                                 cfgets(inputline+i-2,LINEBUF_SIZE-(i-2), bitmaps); // strip comments
2112                 REMOVE_EOL(inputline);
2113                 if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline);
2114                 if (strlen(inputline) == LINEBUF_SIZE-1) {
2115                         Warning("Possible line truncation in BITMAPS.TBL");
2116                         return;
2117                 }
2118                 arg = strtok( inputline, space );
2119                 if (arg && arg[0] == '@') {
2120                         arg++;
2121                         //Registered_only = 1;
2122                 }
2123
2124                 while (arg != NULL) {
2125                         if (*arg == '$')
2126                                 reading_textures = 0; // default
2127                         if (!strcmp(arg, "$TEXTURES")) // BM_TEXTURES
2128                                 reading_textures = 1;
2129                         else if (! stricmp(arg, "$ECLIP") // BM_ECLIP
2130                                    || ! stricmp(arg, "$WCLIP")) // BM_WCLIP
2131                                         texture_count++;
2132                         else // not a special token, must be a bitmap!
2133                                 if (reading_textures) {
2134                                         while (*arg == '\t' || *arg == ' ')
2135                                                 arg++;//remove unwanted blanks
2136                                         if (*arg == '\0')
2137                                                 break;
2138                                         if (d1_tmap_num_unique(texture_count)) {
2139                                                 int d1_index = get_d1_bm_index(arg, d1_pig);
2140                                                 if (d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM) {
2141                                                         d1_tmap_nums[d1_index] = texture_count;
2142                                                         //int d2_index = d2_index_for_d1_index(d1_index);
2143                                                 }
2144                                 }
2145                                 Assert (texture_count < D1_MAX_TEXTURES);
2146                                 texture_count++;
2147                         }
2148
2149                         arg = strtok (NULL, equal_space);
2150                 }
2151         }
2152         cfclose (bitmaps);
2153 }
2154
2155 /* If the given d1_index is the index of a bitmap we have to load
2156  * (because it is unique to descent 1), then returns the d2_index that
2157  * the given d1_index replaces.
2158  * Returns -1 if the given d1_index is not unique to descent 1.
2159  */
2160 short d2_index_for_d1_index(short d1_index)
2161 {
2162         Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
2163         if (! d1_tmap_nums || d1_tmap_nums[d1_index] == -1
2164             || ! d1_tmap_num_unique(d1_tmap_nums[d1_index]))
2165                 return -1;
2166
2167         return Textures[convert_d1_tmap_num(d1_tmap_nums[d1_index])].index;
2168 }
2169
2170 #define D1_BITMAPS_SIZE 300000
2171 void load_d1_bitmap_replacements()
2172 {
2173         CFILE * d1_Piggy_fp;
2174         DiskBitmapHeader bmh;
2175         int pig_data_start, bitmap_header_start, bitmap_data_start;
2176         int N_bitmaps;
2177         short d1_index, d2_index;
2178         ubyte* next_bitmap;
2179         ubyte colormap[256];
2180         ubyte d1_palette[256*3];
2181         char *p;
2182         int pigsize;
2183
2184         d1_Piggy_fp = cfopen( D1_PIGFILE, "rb" );
2185
2186 #define D1_PIG_LOAD_FAILED "Failed loading " D1_PIGFILE
2187         if (!d1_Piggy_fp) {
2188                 Warning(D1_PIG_LOAD_FAILED);
2189                 return;
2190         }
2191
2192         //first, free up data allocated for old bitmaps
2193         free_bitmap_replacements();
2194
2195         if (get_d1_colormap( d1_palette, colormap ) != 0)
2196                 Warning("Could not load descent 1 color palette");
2197
2198         pigsize = cfilelength(d1_Piggy_fp);
2199         switch (pigsize) {
2200         case D1_SHARE_BIG_PIGSIZE:
2201         case D1_SHARE_10_PIGSIZE:
2202         case D1_SHARE_PIGSIZE:
2203         case D1_10_BIG_PIGSIZE:
2204         case D1_10_PIGSIZE:
2205                 pig_data_start = 0;
2206                 // OK, now we need to read d1_tmap_nums by emulating d1's bm_init_use_tbl()
2207                 read_d1_tmap_nums_from_hog(d1_Piggy_fp);
2208                 break;
2209         default:
2210                 Warning("Unknown size for " D1_PIGFILE);
2211                 Int3();
2212                 // fall through
2213         case D1_PIGSIZE:
2214         case D1_OEM_PIGSIZE:
2215         case D1_MAC_PIGSIZE:
2216         case D1_MAC_SHARE_PIGSIZE:
2217                 pig_data_start = cfile_read_int(d1_Piggy_fp );
2218                 bm_read_d1_tmap_nums(d1_Piggy_fp); //was: bm_read_all_d1(fp);
2219                 //for (i = 0; i < 1800; i++) GameBitmapXlat[i] = cfile_read_short(d1_Piggy_fp);
2220                 break;
2221         }
2222
2223         cfseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
2224         N_bitmaps = cfile_read_int(d1_Piggy_fp);
2225         {
2226                 int N_sounds = cfile_read_int(d1_Piggy_fp);
2227                 int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
2228                         + N_sounds * sizeof(DiskSoundHeader);
2229                 bitmap_header_start = pig_data_start + 2 * sizeof(int);
2230                 bitmap_data_start = bitmap_header_start + header_size;
2231         }
2232
2233         MALLOC( Bitmap_replacement_data, ubyte, D1_BITMAPS_SIZE);
2234         if (!Bitmap_replacement_data) {
2235                 Warning(D1_PIG_LOAD_FAILED);
2236                 return;
2237         }
2238         atexit(free_bitmap_replacements);
2239
2240         next_bitmap = Bitmap_replacement_data;
2241
2242         for (d1_index = 1; d1_index <= N_bitmaps; d1_index++ ) {
2243                 d2_index = d2_index_for_d1_index(d1_index);
2244                 // only change bitmaps which are unique to d1
2245                 if (d2_index != -1) {
2246                         cfseek(d1_Piggy_fp, bitmap_header_start + (d1_index-1) * DISKBITMAPHEADER_D1_SIZE, SEEK_SET);
2247                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
2248
2249                         bitmap_read_d1( &GameBitmaps[d2_index], d1_Piggy_fp, bitmap_data_start, &bmh, &next_bitmap, d1_palette, colormap );
2250                         Assert(next_bitmap - Bitmap_replacement_data < D1_BITMAPS_SIZE);
2251                         GameBitmapOffset[d2_index] = 0; // don't try to read bitmap from current d2 pigfile
2252                         GameBitmapFlags[d2_index] = bmh.flags;
2253
2254                         if ( (p = strchr(AllBitmaps[d2_index].name, '#')) /* d2 BM is animated */
2255                              && !(bmh.dflags & DBM_FLAG_ABM) ) { /* d1 bitmap is not animated */
2256                                 int i, len = p - AllBitmaps[d2_index].name;
2257                                 for (i = 0; i < Num_bitmap_files; i++)
2258                                         if (i != d2_index && ! memcmp(AllBitmaps[d2_index].name, AllBitmaps[i].name, len))
2259                                         {
2260                                                 gr_set_bitmap_data(&GameBitmaps[i], NULL);      // free ogl texture
2261                                                 GameBitmaps[i] = GameBitmaps[d2_index];
2262                                                 GameBitmapOffset[i] = 0;
2263                                                 GameBitmapFlags[i] = bmh.flags;
2264                                         }
2265                         }
2266                 }
2267         }
2268
2269         cfclose(d1_Piggy_fp);
2270
2271         last_palette_loaded_pig[0]= 0;  //force pig re-load
2272
2273         texmerge_flush();       //for re-merging with new textures
2274 }
2275
2276
2277 extern int extra_bitmap_num;
2278
2279 /*
2280  * Find and load the named bitmap from descent.pig
2281  * similar to read_extra_bitmap_iff
2282  */
2283 bitmap_index read_extra_bitmap_d1_pig(char *name)
2284 {
2285         bitmap_index bitmap_num;
2286         grs_bitmap * new = &GameBitmaps[extra_bitmap_num];
2287
2288         bitmap_num.index = 0;
2289
2290         {
2291                 CFILE *d1_Piggy_fp;
2292                 DiskBitmapHeader bmh;
2293                 int pig_data_start, bitmap_header_start, bitmap_data_start;
2294                 int i, N_bitmaps;
2295                 ubyte colormap[256];
2296                 ubyte d1_palette[256*3];
2297                 int pigsize;
2298
2299                 d1_Piggy_fp = cfopen(D1_PIGFILE, "rb");
2300
2301                 if (!d1_Piggy_fp)
2302                 {
2303                         Warning(D1_PIG_LOAD_FAILED);
2304                         return bitmap_num;
2305                 }
2306
2307                 if (get_d1_colormap( d1_palette, colormap ) != 0)
2308                         Warning("Could not load descent 1 color palette");
2309
2310                 pigsize = cfilelength(d1_Piggy_fp);
2311                 switch (pigsize) {
2312                 case D1_SHARE_BIG_PIGSIZE:
2313                 case D1_SHARE_10_PIGSIZE:
2314                 case D1_SHARE_PIGSIZE:
2315                 case D1_10_BIG_PIGSIZE:
2316                 case D1_10_PIGSIZE:
2317                         pig_data_start = 0;
2318                         break;
2319                 default:
2320                         Warning("Unknown size for " D1_PIGFILE);
2321                         Int3();
2322                         // fall through
2323                 case D1_PIGSIZE:
2324                 case D1_OEM_PIGSIZE:
2325                 case D1_MAC_PIGSIZE:
2326                 case D1_MAC_SHARE_PIGSIZE:
2327                         pig_data_start = cfile_read_int(d1_Piggy_fp );
2328
2329                         break;
2330                 }
2331
2332                 cfseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
2333                 N_bitmaps = cfile_read_int(d1_Piggy_fp);
2334                 {
2335                         int N_sounds = cfile_read_int(d1_Piggy_fp);
2336                         int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
2337                                 + N_sounds * sizeof(DiskSoundHeader);
2338                         bitmap_header_start = pig_data_start + 2 * sizeof(int);
2339                         bitmap_data_start = bitmap_header_start + header_size;
2340                 }
2341
2342                 for (i = 1; i <= N_bitmaps; i++)
2343                 {
2344                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
2345                         if (!strnicmp(bmh.name, name, 8))
2346                                 break;
2347                 }
2348
2349                 if (strnicmp(bmh.name, name, 8))
2350                 {
2351                         con_printf(CON_DEBUG, "could not find bitmap %s\n", name);
2352                         return bitmap_num;
2353                 }
2354
2355                 bitmap_read_d1( new, d1_Piggy_fp, bitmap_data_start, &bmh, 0, d1_palette, colormap );
2356
2357                 cfclose(d1_Piggy_fp);
2358         }
2359
2360         new->avg_color = 0;     //compute_average_pixel(new);
2361
2362         bitmap_num.index = extra_bitmap_num;
2363
2364         GameBitmaps[extra_bitmap_num++] = *new;
2365
2366         return bitmap_num;
2367 }
2368
2369
2370 #ifndef FAST_FILE_IO
2371 /*
2372  * reads a bitmap_index structure from a CFILE
2373  */
2374 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
2375 {
2376         bi->index = cfile_read_short(fp);
2377 }
2378
2379 /*
2380  * reads n bitmap_index structs from a CFILE
2381  */
2382 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
2383 {
2384         int i;
2385
2386         for (i = 0; i < n; i++)
2387                 bi[i].index = cfile_read_short(fp);
2388         return i;
2389 }
2390 #endif // FAST_FILE_IO