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