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