call bm_read_all even if EDITOR is defined
[btb/d2x.git] / main / piggy.c
1 /* $Id: piggy.c,v 1.61 2005-01-25 21:53:41 schaffner Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Functions for managing the pig files.
18  *
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <conf.h>
24 #endif
25
26 #ifdef RCS
27 static char rcsid[] = "$Id: piggy.c,v 1.61 2005-01-25 21:53:41 schaffner Exp $";
28 #endif
29
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "pstypes.h"
35 #include "strutil.h"
36 #include "inferno.h"
37 #include "gr.h"
38 #include "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         WIN(DDGRLOCK(dd_grd_curcanv));
1244                 gr_set_curfont( SMALL_FONT );
1245                 gr_set_fontcolor(gr_find_closest_color_current( 20, 20, 20 ),-1 );
1246                 gr_printf( 0x8000, grd_curcanv->cv_h-20, "%s...", TXT_LOADING_DATA );
1247         WIN(DDGRUNLOCK(dd_grd_curcanv));
1248
1249 #if 1 //def EDITOR //need for d1 mission briefings
1250         piggy_init_pigfile(DEFAULT_PIGFILE);
1251 #endif
1252
1253         snd_ok = ham_ok = read_hamfile();
1254
1255         if (Piggy_hamfile_version >= 3)
1256                 snd_ok = read_sndfile();
1257
1258         atexit(piggy_close);
1259
1260         mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1261         return (ham_ok && snd_ok);               //read ok
1262 }
1263
1264 int piggy_is_needed(int soundnum)
1265 {
1266         int i;
1267
1268         if ( !digi_lomem ) return 1;
1269
1270         for (i=0; i<MAX_SOUNDS; i++ )   {
1271                 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1272                         return 1;
1273         }
1274         return 0;
1275 }
1276
1277
1278 void piggy_read_sounds(void)
1279 {
1280         CFILE * fp = NULL;
1281         ubyte * ptr;
1282         int i, sbytes;
1283         #ifdef MACINTOSH
1284         char name[255];
1285         #endif
1286
1287         ptr = SoundBits;
1288         sbytes = 0;
1289
1290         #ifndef MACINTOSH
1291         fp = cfopen( DEFAULT_SNDFILE, "rb" );
1292         #else
1293         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1294         fp = cfopen( name, "rb");
1295         #endif
1296
1297         if (fp == NULL)
1298                 return;
1299
1300         for (i=0; i<Num_sound_files; i++ )      {
1301                 digi_sound *snd = &GameSounds[i];
1302
1303                 if ( SoundOffset[i] > 0 )       {
1304                         if ( piggy_is_needed(i) )       {
1305                                 cfseek( fp, SoundOffset[i], SEEK_SET );
1306
1307                                 // Read in the sound data!!!
1308                                 snd->data = ptr;
1309                                 ptr += snd->length;
1310                                 sbytes += snd->length;
1311                                 cfread( snd->data, snd->length, 1, fp );
1312                         }
1313                         else
1314                                 snd->data = (ubyte *) -1;
1315                 }
1316         }
1317
1318         cfclose(fp);
1319
1320         mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1321
1322 }
1323
1324
1325 extern int descent_critical_error;
1326 extern unsigned descent_critical_deverror;
1327 extern unsigned descent_critical_errcode;
1328
1329 char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \
1330 "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \
1331 "Read fault", "General Failure" };
1332
1333 void piggy_critical_error()
1334 {
1335         grs_canvas * save_canv;
1336         grs_font * save_font;
1337         int i;
1338         save_canv = grd_curcanv;
1339         save_font = grd_curcanv->cv_font;
1340         gr_palette_load( gr_palette );
1341         i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A'  );
1342         if ( i == 1 )
1343                 exit(1);
1344         gr_set_current_canvas(save_canv);
1345         grd_curcanv->cv_font = save_font;
1346 }
1347
1348 extern void gr_set_bitmap_flags(grs_bitmap *pbm, int flags);
1349
1350 void piggy_bitmap_page_in( bitmap_index bitmap )
1351 {
1352         grs_bitmap * bmp;
1353         int i,org_i,temp;
1354
1355         org_i = 0;
1356
1357         i = bitmap.index;
1358         Assert( i >= 0 );
1359         Assert( i < MAX_BITMAP_FILES );
1360         Assert( i < Num_bitmap_files );
1361         Assert( Piggy_bitmap_cache_size > 0 );
1362
1363         if ( i < 1 ) return;
1364         if ( i >= MAX_BITMAP_FILES ) return;
1365         if ( i >= Num_bitmap_files ) return;
1366
1367         if ( GameBitmapOffset[i] == 0 ) return;         // A read-from-disk bitmap!!!
1368
1369         if ( piggy_low_memory ) {
1370                 org_i = i;
1371                 i = GameBitmapXlat[i];          // Xlat for low-memory settings!
1372         }
1373
1374         bmp = &GameBitmaps[i];
1375
1376         if ( bmp->bm_flags & BM_FLAG_PAGED_OUT )        {
1377                 stop_time();
1378
1379         ReDoIt:
1380                 descent_critical_error = 0;
1381                 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1382                 if ( descent_critical_error )   {
1383                         piggy_critical_error();
1384                         goto ReDoIt;
1385                 }
1386
1387                 gr_set_bitmap_flags(bmp, GameBitmapFlags[i]);
1388
1389                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1390                         int zsize = 0, pigsize = cfilelength(Piggy_fp);
1391                         descent_critical_error = 0;
1392                         zsize = cfile_read_int(Piggy_fp);
1393                         if ( descent_critical_error )   {
1394                                 piggy_critical_error();
1395                                 goto ReDoIt;
1396                         }
1397
1398                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1399                         //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
1400                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1401                                 Int3();
1402                                 piggy_bitmap_page_out_all();
1403                                 goto ReDoIt;
1404                         }
1405                         descent_critical_error = 0;
1406                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next+4], 1, zsize-4, Piggy_fp );
1407                         if ( descent_critical_error )   {
1408                                 piggy_critical_error();
1409                                 goto ReDoIt;
1410                         }
1411                         *((int *) (Piggy_bitmap_cache_data + Piggy_bitmap_cache_next)) = INTEL_INT(zsize);
1412                         gr_set_bitmap_data(bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
1413
1414 #ifndef MACDATA
1415                         switch (pigsize) {
1416                         default:
1417                                 if (!FindArg("-macdata"))
1418                                         break;
1419                                 // otherwise, fall through...
1420                         case MAC_ALIEN1_PIGSIZE:
1421                         case MAC_ALIEN2_PIGSIZE:
1422                         case MAC_FIRE_PIGSIZE:
1423                         case MAC_GROUPA_PIGSIZE:
1424                         case MAC_ICE_PIGSIZE:
1425                         case MAC_WATER_PIGSIZE:
1426                                 rle_swap_0_255( bmp );
1427                                 memcpy(&zsize, bmp->bm_data, 4);
1428                                 break;
1429                         }
1430 #endif
1431
1432                         Piggy_bitmap_cache_next += zsize;
1433                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1434                                 Int3();
1435                                 piggy_bitmap_page_out_all();
1436                                 goto ReDoIt;
1437                         }
1438
1439                 } else {
1440                         int pigsize = cfilelength(Piggy_fp);
1441                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1442                         Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
1443                         if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1444                                 piggy_bitmap_page_out_all();
1445                                 goto ReDoIt;
1446                         }
1447                         descent_critical_error = 0;
1448                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1449                         if ( descent_critical_error )   {
1450                                 piggy_critical_error();
1451                                 goto ReDoIt;
1452                         }
1453                         gr_set_bitmap_data(bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
1454                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1455
1456 #ifndef MACDATA
1457                         switch (pigsize) {
1458                         default:
1459                                 if (!FindArg("-macdata"))
1460                                         break;
1461                                 // otherwise, fall through...
1462                         case MAC_ALIEN1_PIGSIZE:
1463                         case MAC_ALIEN2_PIGSIZE:
1464                         case MAC_FIRE_PIGSIZE:
1465                         case MAC_GROUPA_PIGSIZE:
1466                         case MAC_ICE_PIGSIZE:
1467                         case MAC_WATER_PIGSIZE:
1468                                 swap_0_255( bmp );
1469                                 break;
1470                         }
1471 #endif
1472                 }
1473
1474                 //@@if ( bmp->bm_selector ) {
1475                 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1476                 //@@    if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1477                 //@@            Error( "Error modifying selector base in piggy.c\n" );
1478                 //@@#endif
1479                 //@@}
1480
1481                 start_time();
1482         }
1483
1484         if ( piggy_low_memory ) {
1485                 if ( org_i != i )
1486                         GameBitmaps[org_i] = GameBitmaps[i];
1487         }
1488
1489 //@@Removed from John's code:
1490 //@@#ifndef WINDOWS
1491 //@@    if ( bmp->bm_selector ) {
1492 //@@            if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1493 //@@                    Error( "Error modifying selector base in piggy.c\n" );
1494 //@@    }
1495 //@@#endif
1496
1497 }
1498
1499 void piggy_bitmap_page_out_all()
1500 {
1501         int i;
1502         
1503         Piggy_bitmap_cache_next = 0;
1504
1505         piggy_page_flushed++;
1506
1507         texmerge_flush();
1508         rle_cache_flush();
1509
1510         for (i=0; i<Num_bitmap_files; i++ )             {
1511                 if ( GameBitmapOffset[i] > 0 )  {       // Don't page out bitmaps read from disk!!!
1512                         GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1513                         gr_set_bitmap_data(&GameBitmaps[i], NULL);
1514                 }
1515         }
1516
1517         mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1518 }
1519
1520 void piggy_load_level_data()
1521 {
1522         piggy_bitmap_page_out_all();
1523         paging_touch_all();
1524 }
1525
1526 #ifdef EDITOR
1527
1528 void change_filename_ext( char *dest, char *src, char *ext );
1529
1530 void piggy_write_pigfile(char *filename)
1531 {
1532         FILE *pig_fp;
1533         int bitmap_data_start, data_offset;
1534         DiskBitmapHeader bmh;
1535         int org_offset;
1536         char subst_name[32];
1537         int i;
1538         FILE *fp1,*fp2;
1539         char tname[FILENAME_LEN];
1540
1541         // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1542         for (i=0; i < Num_bitmap_files; i++ )   {
1543                 bitmap_index bi;
1544                 bi.index = i;
1545                 PIGGY_PAGE_IN( bi );
1546         }
1547         // -- mprintf( (0, "\n" ));
1548
1549         piggy_close_file();
1550
1551         // -- mprintf( (0, "Creating %s...",filename ));
1552
1553         pig_fp = fopen( filename, "wb" );       //open PIG file
1554         Assert( pig_fp!=NULL );
1555
1556         write_int(PIGFILE_ID,pig_fp);
1557         write_int(PIGFILE_VERSION,pig_fp);
1558
1559         Num_bitmap_files--;
1560         fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1561         Num_bitmap_files++;
1562
1563         bitmap_data_start = ftell(pig_fp);
1564         bitmap_data_start += (Num_bitmap_files - 1) * sizeof(DiskBitmapHeader);
1565         data_offset = bitmap_data_start;
1566
1567         change_filename_ext(tname,filename,"lst");
1568         fp1 = fopen( tname, "wt" );
1569         change_filename_ext(tname,filename,"all");
1570         fp2 = fopen( tname, "wt" );
1571
1572         for (i=1; i < Num_bitmap_files; i++ )   {
1573                 int *size;
1574                 grs_bitmap *bmp;
1575
1576                 {               
1577                         char * p, *p1;
1578                         p = strchr(AllBitmaps[i].name, '#');
1579                         if (p) {   // this is an ABM == animated bitmap
1580                                 int n;
1581                                 p1 = p; p1++; 
1582                                 n = atoi(p1);
1583                                 *p = 0;
1584                                 if (fp2 && n==0)
1585                                         fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1586                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1587                                 Assert( n <= DBM_NUM_FRAMES );
1588                                 bmh.dflags = DBM_FLAG_ABM + n;
1589                                 *p = '#';
1590                         } else {
1591                                 if (fp2)
1592                                         fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1593                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1594                                 bmh.dflags = 0;
1595                         }
1596                 }
1597                 bmp = &GameBitmaps[i];
1598
1599                 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1600
1601                 if (fp1)
1602                         fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1603                 org_offset = ftell(pig_fp);
1604                 bmh.offset = data_offset - bitmap_data_start;
1605                 fseek( pig_fp, data_offset, SEEK_SET );
1606
1607                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1608                         size = (int *)bmp->bm_data;
1609                         fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1610                         data_offset += *size;
1611                         if (fp1)
1612                                 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1613                 } else {
1614                         fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1615                         data_offset += bmp->bm_rowsize * bmp->bm_h;
1616                         if (fp1)
1617                                 fprintf( fp1, ".\n" );
1618                 }
1619                 fseek( pig_fp, org_offset, SEEK_SET );
1620                 Assert( GameBitmaps[i].bm_w < 4096 );
1621                 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1622                 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1623                 Assert( GameBitmaps[i].bm_h < 4096 );
1624                 bmh.height = GameBitmaps[i].bm_h;
1625                 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1626                 bmh.flags = GameBitmaps[i].bm_flags;
1627                 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name ))    {
1628                         bitmap_index other_bitmap;
1629                         other_bitmap = piggy_find_bitmap( subst_name );
1630                         GameBitmapXlat[i] = other_bitmap.index;
1631                         bmh.flags |= BM_FLAG_PAGED_OUT;
1632                         //mprintf(( 0, "Skipping bitmap %d\n", i ));
1633                         //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1634                 } else  {
1635                         bmh.flags &= ~BM_FLAG_PAGED_OUT;
1636                 }
1637                 bmh.avg_color=GameBitmaps[i].avg_color;
1638                 fwrite(&bmh, sizeof(DiskBitmapHeader), 1, pig_fp);  // Mark as a bitmap
1639         }
1640
1641         fclose(pig_fp);
1642
1643         mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1644         fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1645
1646         fclose(fp1);
1647         fclose(fp2);
1648
1649 }
1650
1651 static void write_int(int i,FILE *file)
1652 {
1653         if (fwrite( &i, sizeof(i), 1, file) != 1)
1654                 Error( "Error reading int in gamesave.c" );
1655
1656 }
1657
1658 void piggy_dump_all()
1659 {
1660         int i, xlat_offset;
1661         FILE * ham_fp;
1662         int org_offset,data_offset=0;
1663         DiskSoundHeader sndh;
1664         int sound_data_start=0;
1665         FILE *fp1,*fp2;
1666
1667         #ifdef NO_DUMP_SOUNDS
1668         Num_sound_files = 0;
1669         Num_sound_files_new = 0;
1670         #endif
1671
1672         if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1673                 return;
1674
1675         fp1 = fopen( "ham.lst", "wt" );
1676         fp2 = fopen( "ham.all", "wt" );
1677
1678         if (Must_write_hamfile || Num_bitmap_files_new) {
1679
1680                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1681         
1682                 ham_fp = fopen( DEFAULT_HAMFILE, "wb" );                       //open HAM file
1683                 Assert( ham_fp!=NULL );
1684         
1685                 write_int(HAMFILE_ID,ham_fp);
1686                 write_int(HAMFILE_VERSION,ham_fp);
1687         
1688                 bm_write_all(ham_fp);
1689                 xlat_offset = ftell(ham_fp);
1690                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1691                 //Dump bitmaps
1692         
1693                 if (Num_bitmap_files_new)
1694                         piggy_write_pigfile(DEFAULT_PIGFILE);
1695         
1696                 //free up memeory used by new bitmaps
1697                 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1698                         d_free(GameBitmaps[i].bm_data);
1699         
1700                 //next thing must be done after pig written
1701                 fseek( ham_fp, xlat_offset, SEEK_SET );
1702                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1703         
1704                 fclose(ham_fp);
1705                 mprintf( (0, "\n" ));
1706         }
1707         
1708         if (Num_sound_files_new) {
1709
1710                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1711                 // Now dump sound file
1712                 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1713                 Assert( ham_fp!=NULL );
1714         
1715                 write_int(SNDFILE_ID,ham_fp);
1716                 write_int(SNDFILE_VERSION,ham_fp);
1717
1718                 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1719         
1720                 mprintf( (0, "\nDumping sounds..." ));
1721         
1722                 sound_data_start = ftell(ham_fp);
1723                 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1724                 data_offset = sound_data_start;
1725         
1726                 for (i=0; i < Num_sound_files; i++ )    {
1727                         digi_sound *snd;
1728         
1729                         snd = &GameSounds[i];
1730                         strcpy( sndh.name, AllSounds[i].name );
1731                         sndh.length = GameSounds[i].length;
1732                         sndh.offset = data_offset - sound_data_start;
1733         
1734                         org_offset = ftell(ham_fp);
1735                         fseek( ham_fp, data_offset, SEEK_SET );
1736         
1737                         sndh.data_length = GameSounds[i].length;
1738                         fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1739                         data_offset += snd->length;
1740                         fseek( ham_fp, org_offset, SEEK_SET );
1741                         fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp );                    // Mark as a bitmap
1742         
1743                         fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1744                         fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1745                 }
1746
1747                 fclose(ham_fp);
1748                 mprintf( (0, "\n" ));
1749         }
1750
1751         fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1752         mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1753         fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1754
1755         fclose(fp1);
1756         fclose(fp2);
1757
1758         // Never allow the game to run after building ham.
1759         exit(0);
1760 }
1761
1762 #endif
1763
1764 void piggy_close()
1765 {
1766         piggy_close_file();
1767
1768         if (BitmapBits)
1769                 d_free(BitmapBits);
1770
1771         if ( SoundBits )
1772                 d_free( SoundBits );
1773
1774         hashtable_free( &AllBitmapsNames );
1775         hashtable_free( &AllDigiSndNames );
1776
1777 }
1778
1779 int piggy_does_bitmap_exist_slow( char * name )
1780 {
1781         int i;
1782
1783         for (i=0; i<Num_bitmap_files; i++ )     {
1784                 if ( !strcmp( AllBitmaps[i].name, name) )
1785                         return 1;
1786         }
1787         return 0;
1788 }
1789
1790
1791 #define NUM_GAUGE_BITMAPS 23
1792 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1793         "gauge01", "gauge01b",
1794         "gauge02", "gauge02b",
1795         "gauge06", "gauge06b",
1796         "targ01", "targ01b",
1797         "targ02", "targ02b", 
1798         "targ03", "targ03b",
1799         "targ04", "targ04b",
1800         "targ05", "targ05b",
1801         "targ06", "targ06b",
1802         "gauge18", "gauge18b",
1803         "gauss1", "helix1",
1804         "phoenix1"
1805 };
1806
1807
1808 int piggy_is_gauge_bitmap( char * base_name )
1809 {
1810         int i;
1811         for (i=0; i<NUM_GAUGE_BITMAPS; i++ )    {
1812                 if ( !stricmp( base_name, gauge_bitmap_names[i] ))      
1813                         return 1;
1814         }
1815
1816         return 0;       
1817 }
1818
1819 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1820 {
1821         int frame;
1822         char * p;
1823         char base_name[ 16 ];
1824         
1825         strcpy( subst_name, name );
1826         p = strchr( subst_name, '#' );
1827         if ( p )        {
1828                 frame = atoi( &p[1] );
1829                 *p = 0;
1830                 strcpy( base_name, subst_name );
1831                 if ( !piggy_is_gauge_bitmap( base_name ))       {
1832                         sprintf( subst_name, "%s#%d", base_name, frame+1 );
1833                         if ( piggy_does_bitmap_exist_slow( subst_name )  )      {
1834                                 if ( frame & 1 ) {
1835                                         sprintf( subst_name, "%s#%d", base_name, frame-1 );
1836                                         return 1;
1837                                 }
1838                         }
1839                 }
1840         }
1841         strcpy( subst_name, name );
1842         return 0;
1843 }
1844
1845
1846
1847 #ifdef WINDOWS
1848 //      New Windows stuff
1849
1850 //      windows bitmap page in
1851 //              Page in a bitmap, if ddraw, then page it into a ddsurface in 
1852 //              'video' memory.  if that fails, page it in normally.
1853
1854 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1855 {
1856 }
1857
1858
1859 //      Essential when switching video modes!
1860
1861 void piggy_bitmap_page_out_all_w()
1862 {
1863 }
1864
1865 #endif // WINDOWS
1866
1867
1868 /*
1869  * Functions for loading replacement textures
1870  *  1) From .pog files
1871  *  2) From descent.pig (for loading d1 levels)
1872  */
1873
1874 extern void change_filename_extension( char *dest, char *src, char *new_ext );
1875 extern char last_palette_loaded_pig[];
1876
1877 void free_bitmap_replacements()
1878 {
1879         if (Bitmap_replacement_data) {
1880                 d_free(Bitmap_replacement_data);
1881                 Bitmap_replacement_data = NULL;
1882         }
1883 }
1884
1885 void load_bitmap_replacements(char *level_name)
1886 {
1887         char ifile_name[FILENAME_LEN];
1888         CFILE *ifile;
1889         int i;
1890
1891         //first, free up data allocated for old bitmaps
1892         free_bitmap_replacements();
1893
1894         change_filename_extension(ifile_name, level_name, ".POG" );
1895
1896         ifile = cfopen(ifile_name,"rb");
1897
1898         if (ifile) {
1899                 int id,version,n_bitmaps;
1900                 int bitmap_data_size;
1901                 ushort *indices;
1902
1903                 id = cfile_read_int(ifile);
1904                 version = cfile_read_int(ifile);
1905
1906                 if (id != MAKE_SIG('G','O','P','D') || version != 1) {
1907                         cfclose(ifile);
1908                         return;
1909                 }
1910
1911                 n_bitmaps = cfile_read_int(ifile);
1912
1913                 MALLOC( indices, ushort, n_bitmaps );
1914
1915                 for (i = 0; i < n_bitmaps; i++)
1916                         indices[i] = cfile_read_short(ifile);
1917
1918                 bitmap_data_size = cfilelength(ifile) - cftell(ifile) - sizeof(DiskBitmapHeader) * n_bitmaps;
1919                 MALLOC( Bitmap_replacement_data, ubyte, bitmap_data_size );
1920
1921                 for (i=0;i<n_bitmaps;i++) {
1922                         DiskBitmapHeader bmh;
1923                         grs_bitmap *bm = &GameBitmaps[indices[i]];
1924                         int width;
1925
1926                         DiskBitmapHeader_read(&bmh, ifile);
1927
1928                         width = bmh.width + ((short) (bmh.wh_extra & 0x0f) << 8);
1929                         gr_set_bitmap_data(bm, NULL);   // free ogl texture
1930                         gr_init_bitmap(bm, 0, 0, 0, width, bmh.height + ((short) (bmh.wh_extra & 0xf0) << 4), width, NULL);
1931                         bm->avg_color = bmh.avg_color;
1932                         bm->bm_data = (ubyte *) bmh.offset;
1933
1934                         gr_set_bitmap_flags(bm, bmh.flags & BM_FLAGS_TO_COPY);
1935
1936                         GameBitmapOffset[indices[i]] = 0; // don't try to read bitmap from current pigfile
1937                 }
1938
1939                 cfread(Bitmap_replacement_data,1,bitmap_data_size,ifile);
1940
1941                 for (i = 0; i < n_bitmaps; i++)
1942                 {
1943                         grs_bitmap *bm = &GameBitmaps[indices[i]];
1944                         gr_set_bitmap_data(bm, Bitmap_replacement_data + (int) bm->bm_data);
1945                 }
1946
1947                 d_free(indices);
1948
1949                 cfclose(ifile);
1950
1951                 last_palette_loaded_pig[0]= 0;  //force pig re-load
1952
1953                 texmerge_flush();       //for re-merging with new textures
1954         }
1955
1956         atexit(free_bitmap_replacements);
1957 }
1958
1959 /* calculate table to translate d1 bitmaps to current palette,
1960  * return -1 on error
1961  */
1962 int get_d1_colormap( ubyte *d1_palette, ubyte *colormap )
1963 {
1964         int freq[256];
1965         CFILE * palette_file = cfopen(D1_PALETTE, "rb");
1966         if (!palette_file || cfilelength(palette_file) != 9472)
1967                 return -1;
1968         cfread( d1_palette, 256, 3, palette_file);
1969         cfclose( palette_file );
1970         build_colormap_good( d1_palette, colormap, freq );
1971         // don't change transparencies:
1972         colormap[254] = 254;
1973         colormap[255] = 255;
1974         return 0;
1975 }
1976
1977 #define JUST_IN_CASE 132 /* is enough for d1 pc registered */
1978 void bitmap_read_d1( grs_bitmap *bitmap, /* read into this bitmap */
1979                      CFILE *d1_Piggy_fp, /* read from this file */
1980                      int bitmap_data_start, /* specific to file */
1981                      DiskBitmapHeader *bmh, /* header info for bitmap */
1982                      ubyte **next_bitmap, /* where to write it (if 0, use malloc) */
1983                      ubyte *d1_palette, /* what palette the bitmap has */
1984                      ubyte *colormap) /* how to translate bitmap's colors */
1985 {
1986         int zsize, pigsize = cfilelength(d1_Piggy_fp);
1987         ubyte *data;
1988         int width;
1989
1990         width = bmh->width + ((short) (bmh->wh_extra & 0x0f) << 8);
1991         gr_set_bitmap_data(bitmap, NULL);       // free ogl texture
1992         gr_init_bitmap(bitmap, 0, 0, 0, width, bmh->height + ((short) (bmh->wh_extra & 0xf0) << 4), width, NULL);
1993         bitmap->avg_color = bmh->avg_color;
1994         gr_set_bitmap_flags(bitmap, bmh->flags & BM_FLAGS_TO_COPY);
1995
1996         cfseek(d1_Piggy_fp, bitmap_data_start + bmh->offset, SEEK_SET);
1997         if (bmh->flags & BM_FLAG_RLE) {
1998                 zsize = cfile_read_int(d1_Piggy_fp);
1999                 cfseek(d1_Piggy_fp, -4, SEEK_CUR);
2000         } else
2001                 zsize = bitmap->bm_h * bitmap->bm_w;
2002
2003         if (next_bitmap) {
2004                 data = *next_bitmap;
2005                 *next_bitmap += zsize;
2006         } else {
2007                 data = d_malloc(zsize + JUST_IN_CASE);
2008         }
2009         if (!data) return;
2010
2011         cfread(data, 1, zsize, d1_Piggy_fp);
2012         gr_set_bitmap_data(bitmap, data);
2013         switch(pigsize) {
2014         case D1_MAC_PIGSIZE:
2015         case D1_MAC_SHARE_PIGSIZE:
2016                 if (bmh->flags & BM_FLAG_RLE)
2017                         rle_swap_0_255(bitmap);
2018                 else
2019                         swap_0_255(bitmap);
2020         }
2021         if (bmh->flags & BM_FLAG_RLE)
2022                 rle_remap(bitmap, colormap);
2023         else
2024                 gr_remap_bitmap_good(bitmap, d1_palette, TRANSPARENCY_COLOR, -1);
2025         if (bmh->flags & BM_FLAG_RLE) { // size of bitmap could have changed!
2026                 int new_size;
2027                 memcpy(&new_size, bitmap->bm_data, 4);
2028                 if (next_bitmap) {
2029                         *next_bitmap += new_size - zsize;
2030                 } else {
2031                         Assert( zsize + JUST_IN_CASE >= new_size );
2032                         bitmap->bm_data = d_realloc(bitmap->bm_data, new_size);
2033                         Assert(bitmap->bm_data);
2034                 }
2035         }
2036 }
2037
2038 #define D1_MAX_TEXTURES 800
2039 #define D1_MAX_TMAP_NUM 1630 // 1621 in descent.pig Mac registered
2040
2041 /* the inverse of the d2 Textures array, but for the descent 1 pigfile.
2042  * "Textures" looks up a d2 bitmap index given a d2 tmap_num.
2043  * "d1_tmap_nums" looks up a d1 tmap_num given a d1 bitmap. "-1" means "None".
2044  */
2045 short *d1_tmap_nums = NULL;
2046
2047 void free_d1_tmap_nums() {
2048         if (d1_tmap_nums) {
2049                 d_free(d1_tmap_nums);
2050                 d1_tmap_nums = NULL;
2051         }
2052 }
2053
2054 void bm_read_d1_tmap_nums(CFILE *d1pig)
2055 {
2056         int i, d1_index;
2057
2058         free_d1_tmap_nums();
2059         cfseek(d1pig, 8, SEEK_SET);
2060         MALLOC(d1_tmap_nums, short, D1_MAX_TMAP_NUM);
2061         for (i = 0; i < D1_MAX_TMAP_NUM; i++)
2062                 d1_tmap_nums[i] = -1;
2063         for (i = 0; i < D1_MAX_TEXTURES; i++) {
2064                 d1_index = cfile_read_short(d1pig);
2065                 Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
2066                 d1_tmap_nums[d1_index] = i;
2067         }
2068         atexit(free_d1_tmap_nums);
2069 }
2070
2071 void remove_char( char * s, char c )
2072 {
2073         char *p;
2074         p = strchr(s,c);
2075         if (p) *p = '\0';
2076 }
2077
2078 #define REMOVE_EOL(s)           remove_char((s),'\n')
2079 #define REMOVE_COMMENTS(s)      remove_char((s),';')
2080 #define REMOVE_DOTS(s)          remove_char((s),'.')
2081 char *space = { " \t" };
2082 char *equal_space = { " \t=" };
2083
2084 // this function is at the same position in the d1 shareware piggy loading 
2085 // algorithm as bm_load_sub in main/bmread.c
2086 int get_d1_bm_index(char *filename, CFILE *d1_pig) {
2087         int i, N_bitmaps;
2088         DiskBitmapHeader bmh;
2089         if (strchr (filename, '.'))
2090                 *strchr (filename, '.') = '\0'; // remove extension
2091         cfseek (d1_pig, 0, SEEK_SET);
2092         N_bitmaps = cfile_read_int (d1_pig);
2093         cfseek (d1_pig, 8, SEEK_SET);
2094         for (i = 1; i <= N_bitmaps; i++) {
2095                 DiskBitmapHeader_d1_read(&bmh, d1_pig);
2096                 if (!strnicmp(bmh.name, filename, 8))
2097                         return i;
2098         }
2099         return -1;
2100 }
2101
2102 // imitate the algorithm of bm_init_use_tbl in main/bmread.c
2103 void read_d1_tmap_nums_from_hog(CFILE *d1_pig)
2104 {
2105 #define LINEBUF_SIZE 600
2106         int reading_textures = 0;
2107         short texture_count = 0;
2108         char inputline[LINEBUF_SIZE];
2109         CFILE * bitmaps;
2110         int bitmaps_tbl_is_binary = 0;
2111         int i;
2112
2113         bitmaps = cfopen ("bitmaps.tbl", "rb");
2114         if (!bitmaps) {
2115                 bitmaps = cfopen ("bitmaps.bin", "rb");
2116                 bitmaps_tbl_is_binary = 1;
2117         }
2118
2119         if (!bitmaps) {
2120                 Warning ("Could not find bitmaps.* for reading d1 textures");
2121                 return;
2122         }
2123
2124         free_d1_tmap_nums();
2125         MALLOC(d1_tmap_nums, short, D1_MAX_TMAP_NUM);
2126         for (i = 0; i < D1_MAX_TMAP_NUM; i++)
2127                 d1_tmap_nums[i] = -1;
2128         atexit(free_d1_tmap_nums);
2129
2130         while (cfgets (inputline, LINEBUF_SIZE, bitmaps)) {
2131                 char *arg;
2132
2133                 if (bitmaps_tbl_is_binary)
2134                         decode_text_line((inputline));
2135                 else
2136                         while (inputline[(i=strlen(inputline))-2]=='\\')
2137                                 cfgets(inputline+i-2,LINEBUF_SIZE-(i-2), bitmaps); // strip comments
2138                 REMOVE_EOL(inputline);
2139                 if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline);
2140                 if (strlen(inputline) == LINEBUF_SIZE-1) {
2141                         Warning("Possible line truncation in BITMAPS.TBL");
2142                         return;
2143                 }
2144                 arg = strtok( inputline, space );
2145                 if (arg && arg[0] == '@') {
2146                         arg++;
2147                         //Registered_only = 1;
2148                 }
2149
2150                 while (arg != NULL) {
2151                         if (*arg == '$')
2152                                 reading_textures = 0; // default
2153                         if (!strcmp(arg, "$TEXTURES")) // BM_TEXTURES
2154                                 reading_textures = 1;
2155                         else if (! stricmp(arg, "$ECLIP") // BM_ECLIP
2156                                    || ! stricmp(arg, "$WCLIP")) // BM_WCLIP
2157                                         texture_count++;
2158                         else // not a special token, must be a bitmap!
2159                                 if (reading_textures) {
2160                                         while (*arg == '\t' || *arg == ' ')
2161                                                 arg++;//remove unwanted blanks
2162                                         if (*arg == '\0')
2163                                                 break;
2164                                         if (d1_tmap_num_unique(texture_count)) {
2165                                                 int d1_index = get_d1_bm_index(arg, d1_pig);
2166                                                 if (d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM) {
2167                                                         d1_tmap_nums[d1_index] = texture_count;
2168                                                         //int d2_index = d2_index_for_d1_index(d1_index);
2169                                                 }
2170                                 }
2171                                 Assert (texture_count < D1_MAX_TEXTURES);
2172                                 texture_count++;
2173                         }
2174
2175                         arg = strtok (NULL, equal_space);
2176                 }
2177         }
2178         cfclose (bitmaps);
2179 }
2180
2181 /* If the given d1_index is the index of a bitmap we have to load
2182  * (because it is unique to descent 1), then returns the d2_index that
2183  * the given d1_index replaces.
2184  * Returns -1 if the given d1_index is not unique to descent 1.
2185  */
2186 short d2_index_for_d1_index(short d1_index)
2187 {
2188         Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
2189         if (! d1_tmap_nums || d1_tmap_nums[d1_index] == -1
2190             || ! d1_tmap_num_unique(d1_tmap_nums[d1_index]))
2191                 return -1;
2192
2193         return Textures[convert_d1_tmap_num(d1_tmap_nums[d1_index])].index;
2194 }
2195
2196 #define D1_BITMAPS_SIZE 300000
2197 void load_d1_bitmap_replacements()
2198 {
2199         CFILE * d1_Piggy_fp;
2200         DiskBitmapHeader bmh;
2201         int pig_data_start, bitmap_header_start, bitmap_data_start;
2202         int N_bitmaps;
2203         short d1_index, d2_index;
2204         ubyte* next_bitmap;
2205         ubyte colormap[256];
2206         ubyte d1_palette[256*3];
2207         char *p;
2208         int pigsize;
2209
2210         d1_Piggy_fp = cfopen( D1_PIGFILE, "rb" );
2211
2212 #define D1_PIG_LOAD_FAILED "Failed loading " D1_PIGFILE
2213         if (!d1_Piggy_fp) {
2214                 Warning(D1_PIG_LOAD_FAILED);
2215                 return;
2216         }
2217
2218         //first, free up data allocated for old bitmaps
2219         free_bitmap_replacements();
2220
2221         Assert( get_d1_colormap( d1_palette, colormap ) == 0 );
2222
2223         pigsize = cfilelength(d1_Piggy_fp);
2224         switch (pigsize) {
2225         case D1_SHARE_BIG_PIGSIZE:
2226         case D1_SHARE_10_PIGSIZE:
2227         case D1_SHARE_PIGSIZE:
2228         case D1_10_BIG_PIGSIZE:
2229         case D1_10_PIGSIZE:
2230                 pig_data_start = 0;
2231                 // OK, now we need to read d1_tmap_nums by emulating d1's bm_init_use_tbl()
2232                 read_d1_tmap_nums_from_hog(d1_Piggy_fp);
2233                 break;
2234         default:
2235                 Warning("Unknown size for " D1_PIGFILE);
2236                 Int3();
2237                 // fall through
2238         case D1_PIGSIZE:
2239         case D1_OEM_PIGSIZE:
2240         case D1_MAC_PIGSIZE:
2241         case D1_MAC_SHARE_PIGSIZE:
2242                 pig_data_start = cfile_read_int(d1_Piggy_fp );
2243                 bm_read_d1_tmap_nums(d1_Piggy_fp); //was: bm_read_all_d1(fp);
2244                 //for (i = 0; i < 1800; i++) GameBitmapXlat[i] = cfile_read_short(d1_Piggy_fp);
2245                 break;
2246         }
2247
2248         cfseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
2249         N_bitmaps = cfile_read_int(d1_Piggy_fp);
2250         {
2251                 int N_sounds = cfile_read_int(d1_Piggy_fp);
2252                 int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
2253                         + N_sounds * sizeof(DiskSoundHeader);
2254                 bitmap_header_start = pig_data_start + 2 * sizeof(int);
2255                 bitmap_data_start = bitmap_header_start + header_size;
2256         }
2257
2258         MALLOC( Bitmap_replacement_data, ubyte, D1_BITMAPS_SIZE);
2259         if (!Bitmap_replacement_data) {
2260                 Warning(D1_PIG_LOAD_FAILED);
2261                 return;
2262         }
2263         atexit(free_bitmap_replacements);
2264
2265         next_bitmap = Bitmap_replacement_data;
2266
2267         for (d1_index = 1; d1_index <= N_bitmaps; d1_index++ ) {
2268                 d2_index = d2_index_for_d1_index(d1_index);
2269                 // only change bitmaps which are unique to d1
2270                 if (d2_index != -1) {
2271                         cfseek(d1_Piggy_fp, bitmap_header_start + (d1_index-1) * DISKBITMAPHEADER_D1_SIZE, SEEK_SET);
2272                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
2273
2274                         bitmap_read_d1( &GameBitmaps[d2_index], d1_Piggy_fp, bitmap_data_start, &bmh, &next_bitmap, d1_palette, colormap );
2275                         Assert(next_bitmap - Bitmap_replacement_data < D1_BITMAPS_SIZE);
2276                         GameBitmapOffset[d2_index] = 0; // don't try to read bitmap from current d2 pigfile
2277                         GameBitmapFlags[d2_index] = bmh.flags;
2278
2279                         if ( (p = strchr(AllBitmaps[d2_index].name, '#')) /* d2 BM is animated */
2280                              && !(bmh.dflags & DBM_FLAG_ABM) ) { /* d1 bitmap is not animated */
2281                                 int i, len = p - AllBitmaps[d2_index].name;
2282                                 for (i = 0; i < Num_bitmap_files; i++)
2283                                         if (i != d2_index && ! memcmp(AllBitmaps[d2_index].name, AllBitmaps[i].name, len))
2284                                         {
2285                                                 gr_set_bitmap_data(&GameBitmaps[i], NULL);      // free ogl texture
2286                                                 GameBitmaps[i] = GameBitmaps[d2_index];
2287                                                 GameBitmapOffset[i] = 0;
2288                                                 GameBitmapFlags[i] = bmh.flags;
2289                                         }
2290                         }
2291                 }
2292         }
2293
2294         cfclose(d1_Piggy_fp);
2295
2296         last_palette_loaded_pig[0]= 0;  //force pig re-load
2297
2298         texmerge_flush();       //for re-merging with new textures
2299 }
2300
2301
2302 extern int extra_bitmap_num;
2303
2304 /*
2305  * Find and load the named bitmap from descent.pig
2306  * similar to read_extra_bitmap_iff
2307  */
2308 bitmap_index read_extra_bitmap_d1_pig(char *name)
2309 {
2310         bitmap_index bitmap_num;
2311         grs_bitmap * new = &GameBitmaps[extra_bitmap_num];
2312
2313         bitmap_num.index = 0;
2314
2315         {
2316                 CFILE *d1_Piggy_fp;
2317                 DiskBitmapHeader bmh;
2318                 int pig_data_start, bitmap_header_start, bitmap_data_start;
2319                 int i, N_bitmaps;
2320                 ubyte colormap[256];
2321                 ubyte d1_palette[256*3];
2322                 int pigsize;
2323
2324                 d1_Piggy_fp = cfopen(D1_PIGFILE, "rb");
2325
2326                 if (!d1_Piggy_fp)
2327                 {
2328                         Warning(D1_PIG_LOAD_FAILED);
2329                         return bitmap_num;
2330                 }
2331
2332                 Assert( get_d1_colormap( d1_palette, colormap ) == 0 );
2333
2334                 pigsize = cfilelength(d1_Piggy_fp);
2335                 switch (pigsize) {
2336                 case D1_SHARE_BIG_PIGSIZE:
2337                 case D1_SHARE_10_PIGSIZE:
2338                 case D1_SHARE_PIGSIZE:
2339                 case D1_10_BIG_PIGSIZE:
2340                 case D1_10_PIGSIZE:
2341                         pig_data_start = 0;
2342                         break;
2343                 default:
2344                         Warning("Unknown size for " D1_PIGFILE);
2345                         Int3();
2346                         // fall through
2347                 case D1_PIGSIZE:
2348                 case D1_OEM_PIGSIZE:
2349                 case D1_MAC_PIGSIZE:
2350                 case D1_MAC_SHARE_PIGSIZE:
2351                         pig_data_start = cfile_read_int(d1_Piggy_fp );
2352
2353                         break;
2354                 }
2355
2356                 cfseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
2357                 N_bitmaps = cfile_read_int(d1_Piggy_fp);
2358                 {
2359                         int N_sounds = cfile_read_int(d1_Piggy_fp);
2360                         int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
2361                                 + N_sounds * sizeof(DiskSoundHeader);
2362                         bitmap_header_start = pig_data_start + 2 * sizeof(int);
2363                         bitmap_data_start = bitmap_header_start + header_size;
2364                 }
2365
2366                 for (i = 1; i <= N_bitmaps; i++)
2367                 {
2368                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
2369                         if (!strnicmp(bmh.name, name, 8))
2370                                 break;
2371                 }
2372
2373                 if (strnicmp(bmh.name, name, 8))
2374                 {
2375                         con_printf(CON_DEBUG, "could not find bitmap %s\n", name);
2376                         return bitmap_num;
2377                 }
2378
2379                 bitmap_read_d1( new, d1_Piggy_fp, bitmap_data_start, &bmh, 0, d1_palette, colormap );
2380
2381                 cfclose(d1_Piggy_fp);
2382         }
2383
2384         new->avg_color = 0;     //compute_average_pixel(new);
2385
2386         bitmap_num.index = extra_bitmap_num;
2387
2388         GameBitmaps[extra_bitmap_num++] = *new;
2389
2390         return bitmap_num;
2391 }
2392
2393
2394 #ifndef FAST_FILE_IO
2395 /*
2396  * reads a bitmap_index structure from a CFILE
2397  */
2398 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
2399 {
2400         bi->index = cfile_read_short(fp);
2401 }
2402
2403 /*
2404  * reads n bitmap_index structs from a CFILE
2405  */
2406 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
2407 {
2408         int i;
2409
2410         for (i = 0; i < n; i++)
2411                 bi[i].index = cfile_read_short(fp);
2412         return i;
2413 }
2414 #endif // FAST_FILE_IO