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