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