]> icculus.org git repositories - btb/d2x.git/blob - main/piggy.c
mac data file loading
[btb/d2x.git] / main / piggy.c
1 /* $Id: piggy.c,v 1.16 2002-08-15 05:49:23 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 #ifdef HAVE_CONFIG_H
16 #include <conf.h>
17 #endif
18
19 #ifdef RCS
20 static char rcsid[] = "$Id: piggy.c,v 1.16 2002-08-15 05:49:23 btb Exp $";
21 #endif
22
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "pstypes.h"
28 #include "strutil.h"
29 #include "inferno.h"
30 #include "gr.h"
31 #include "u_mem.h"
32 #include "iff.h"
33 #include "mono.h"
34 #include "error.h"
35 #include "sounds.h"
36 #include "songs.h"
37 #include "bm.h"
38 #include "bmread.h"
39 #include "hash.h"
40 #include "args.h"
41 #include "palette.h"
42 #include "gamefont.h"
43 #include "rle.h"
44 #include "screens.h"
45 #include "piggy.h"
46 #include "texmerge.h"
47 #include "paging.h"
48 #include "game.h"
49 #include "text.h"
50 #include "cfile.h"
51 #include "newmenu.h"
52 #include "byteswap.h"
53 #include "findfile.h"
54 #include "makesig.h"
55
56 #ifndef MACINTOSH
57 //      #include "unarj.h"
58 #else
59         #include <Strings.h>            // MacOS Toolbox header
60         #include <Files.h>
61         #include <unistd.h>
62 #endif
63
64 //#define NO_DUMP_SOUNDS        1   //if set, dump bitmaps but not sounds
65
66 #define DEFAULT_PIGFILE_REGISTERED      "groupa.pig"
67 #define DEFAULT_PIGFILE_SHAREWARE       "d2demo.pig"
68 #define DEFAULT_HAMFILE_REGISTERED      "descent2.ham"
69 #define DEFAULT_HAMFILE_SHAREWARE       "d2demo.ham"
70
71 #define DEFAULT_PIGFILE (cfexist(DEFAULT_PIGFILE_REGISTERED)?DEFAULT_PIGFILE_REGISTERED:DEFAULT_PIGFILE_SHAREWARE)
72 #define DEFAULT_HAMFILE (cfexist(DEFAULT_HAMFILE_REGISTERED)?DEFAULT_HAMFILE_REGISTERED:DEFAULT_HAMFILE_SHAREWARE)
73 #define DEFAULT_SNDFILE ((Piggy_hamfile_version < 3)?DEFAULT_HAMFILE_SHAREWARE:(digi_sample_rate==SAMPLE_RATE_22K)?"descent2.s22":"descent2.s11")
74
75 int Gr_transparency_color = 255;
76
77 ubyte *BitmapBits = NULL;
78 ubyte *SoundBits = NULL;
79
80 typedef struct BitmapFile {
81         char    name[15];
82 } BitmapFile;
83
84 typedef struct SoundFile {
85         char    name[15];
86 } SoundFile;
87
88 hashtable AllBitmapsNames;
89 hashtable AllDigiSndNames;
90
91 int Num_bitmap_files = 0;
92 int Num_sound_files = 0;
93
94 digi_sound GameSounds[MAX_SOUND_FILES];
95 int SoundOffset[MAX_SOUND_FILES];
96 grs_bitmap GameBitmaps[MAX_BITMAP_FILES];
97
98 alias alias_list[MAX_ALIASES];
99 int Num_aliases=0;
100
101 int Must_write_hamfile = 0;
102 int Num_bitmap_files_new = 0;
103 int Num_sound_files_new = 0;
104 BitmapFile AllBitmaps[ MAX_BITMAP_FILES ];
105 static SoundFile AllSounds[ MAX_SOUND_FILES ];
106
107 int Piggy_hamfile_version = 0;
108
109 int piggy_low_memory = 0;
110
111 int Piggy_bitmap_cache_size = 0;
112 int Piggy_bitmap_cache_next = 0;
113 ubyte * Piggy_bitmap_cache_data = NULL;
114 static int GameBitmapOffset[MAX_BITMAP_FILES];
115 static ubyte GameBitmapFlags[MAX_BITMAP_FILES];
116 ushort GameBitmapXlat[MAX_BITMAP_FILES];
117
118 #define PIGGY_BUFFER_SIZE (2400*1024)
119
120 #ifdef MACINTOSH
121 #define PIGGY_SMALL_BUFFER_SIZE (1400*1024)             // size of buffer when piggy_low_memory is set
122
123 #ifdef SHAREWARE
124 #undef PIGGY_BUFFER_SIZE
125 #undef PIGGY_SMALL_BUFFER_SIZE
126
127 #define PIGGY_BUFFER_SIZE (2000*1024)
128 #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024)
129 #endif          // SHAREWARE
130
131 #endif
132
133 int piggy_page_flushed = 0;
134
135 #define DBM_FLAG_ABM            64
136
137 ubyte BigPig = 0;
138
139 #ifdef MACINTOSH
140         extern short    cd_VRefNum;
141         extern void             ConcatPStr(StringPtr dst, StringPtr src);
142         extern int              ConvertPToCStr(StringPtr inPStr, char* outCStrBuf);
143         extern int              ConvertCToPStr(char* inCStr, StringPtr outPStrBuf);
144 #endif
145
146 int piggy_is_substitutable_bitmap( char * name, char * subst_name );
147
148 #ifdef EDITOR
149 void piggy_write_pigfile(char *filename);
150 static void write_int(int i,FILE *file);
151 #endif
152
153 void swap_0_255(grs_bitmap *bmp)
154 {
155         int i;
156
157         for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) {
158                 if(bmp->bm_data[i] == 0)
159                         bmp->bm_data[i] = 255;
160                 else if (bmp->bm_data[i] == 255)
161                         bmp->bm_data[i] = 0;
162         }
163 }
164
165 bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file )
166 {
167         bitmap_index temp;
168         Assert( Num_bitmap_files < MAX_BITMAP_FILES );
169
170         temp.index = Num_bitmap_files;
171
172         if (!in_file)   {
173 #ifdef EDITOR
174                 if ( FindArg("-macdata") )
175                         swap_0_255( bmp );
176 #endif
177                 if ( !BigPig )  gr_bitmap_rle_compress( bmp );
178                 Num_bitmap_files_new++;
179         }
180
181         strncpy( AllBitmaps[Num_bitmap_files].name, name, 12 );
182         hashtable_insert( &AllBitmapsNames, AllBitmaps[Num_bitmap_files].name, Num_bitmap_files );
183         GameBitmaps[Num_bitmap_files] = *bmp;
184         if ( !in_file ) {
185                 GameBitmapOffset[Num_bitmap_files] = 0;
186                 GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags;
187         }
188         Num_bitmap_files++;
189
190         return temp;
191 }
192
193 int piggy_register_sound( digi_sound * snd, char * name, int in_file )
194 {
195         int i;
196
197         Assert( Num_sound_files < MAX_SOUND_FILES );
198
199         strncpy( AllSounds[Num_sound_files].name, name, 12 );
200         hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files );
201         GameSounds[Num_sound_files] = *snd;
202         if ( !in_file ) {
203                 SoundOffset[Num_sound_files] = 0;       
204         }
205
206         i = Num_sound_files;
207    
208         if (!in_file)
209                 Num_sound_files_new++;
210
211         Num_sound_files++;
212         return i;
213 }
214
215 bitmap_index piggy_find_bitmap( char * name )   
216 {
217         bitmap_index bmp;
218         int i;
219         char *t;
220
221         bmp.index = 0;
222
223         if ((t=strchr(name,'#'))!=NULL)
224                 *t=0;
225
226         for (i=0;i<Num_aliases;i++)
227                 if (stricmp(name,alias_list[i].alias_name)==0) {
228                         if (t) {                //extra stuff for ABMs
229                                 static char temp[FILENAME_LEN];
230                                 _splitpath(alias_list[i].file_name, NULL, NULL, temp, NULL );
231                                 name = temp;
232                                 strcat(name,"#");
233                                 strcat(name,t+1);
234                         }
235                         else
236                                 name=alias_list[i].file_name; 
237                         break;
238                 }
239
240         if (t)
241                 *t = '#';
242
243         i = hashtable_search( &AllBitmapsNames, name );
244         Assert( i != 0 );
245         if ( i < 0 )
246                 return bmp;
247
248         bmp.index = i;
249         return bmp;
250 }
251
252 int piggy_find_sound( char * name )     
253 {
254         int i;
255
256         i = hashtable_search( &AllDigiSndNames, name );
257
258         if ( i < 0 )
259                 return 255;
260
261         return i;
262 }
263
264 CFILE * Piggy_fp = NULL;
265
266 #define FILENAME_LEN 13
267
268 char Current_pigfile[FILENAME_LEN] = "";
269
270 void piggy_close_file()
271 {
272         if ( Piggy_fp ) {
273                 cfclose( Piggy_fp );
274                 Piggy_fp        = NULL;
275                 Current_pigfile[0] = 0;
276         }
277 }
278
279 int Pigfile_initialized=0;
280
281 #define PIGFILE_ID              MAKE_SIG('G','I','P','P') //PPIG
282 #define PIGFILE_VERSION         2
283
284 extern char CDROM_dir[];
285
286 int request_cd(void);
287
288
289 #ifdef MACINTOSH
290
291 //copies a pigfile from the CD to the current dir
292 //retuns file handle of new pig
293 CFILE *copy_pigfile_from_cd(char *filename)             // MACINTOSH VERSION
294 {
295         // C Stuff
296         char                    sourcePathAndFileCStr[255] = "";
297         char                    destPathAndFileCStr[255]        = "";
298         FILEFINDSTRUCT  find;
299         FILE*                   sourceFile      = NULL;
300         FILE*                   destFile        = NULL;
301         const int               BUF_SIZE = 4096;
302         ubyte                   buf[BUF_SIZE];
303
304         // Mac Stuff
305         Str255                  sourcePathAndFilePStr = "\p";
306         Str255                  destPathAndFilePStr = "\p";
307         Str255                  pigfileNamePStr = "\p";
308         HParamBlockRec  theSourcePigHFSParams;
309         HParamBlockRec  theDestPigHFSParams;
310         OSErr                   theErr = noErr;
311         char                    oldDirCStr[255] = "";
312
313         getcwd(oldDirCStr, 255);
314         
315         show_boxed_message("Copying bitmap data from CD...");
316         gr_palette_load(gr_palette);    //I don't think this line is really needed
317
318         chdir(":Data");
319         //First, delete all PIG files currently in the directory
320         if( !FileFindFirst( "*.pig", &find ) )
321         {
322                 do
323                 {
324                         remove(find.name);
325                 } while( !FileFindNext( &find ) );
326                 
327                 FileFindClose();
328         }
329         chdir(oldDirCStr);
330
331         //Now, copy over new pig
332         songs_stop_redbook();           //so we can read off the cd
333
334         // make the source path "<cd volume>:Data:filename.pig"
335 //MWA   ConvertCToPStr(filename, pigfileNamePStr);
336
337 //MWA   ConcatPStr(sourcePathAndFilePStr, "\pDescent II:Data:");        // volume ID is cd_VRefNum
338 //MWA   ConcatPStr(sourcePathAndFilePStr, pigfileNamePStr);
339
340         strupr(filename);
341         strcpy(sourcePathAndFileCStr, "Descent II:Data:");
342         strcat(sourcePathAndFileCStr, filename);
343         
344         // make the destination path "<default directory>:Data:filename.pig"
345 //MWA   ConcatPStr(destPathAndFilePStr, "\p:Data:");
346 //MWA   ConcatPStr(destPathAndFilePStr, pigfileNamePStr);
347 //MWA   ConvertPToCStr(sourcePathAndFilePStr, sourcePathAndFileCStr);
348 //MWA   ConvertPToCStr(destPathAndFilePStr, destPathAndFileCStr);
349
350         strcpy(destPathAndFileCStr, ":Data:");
351         strcat(destPathAndFileCStr, filename);
352
353         strcpy(sourcePathAndFilePStr, sourcePathAndFileCStr);
354         strcpy(destPathAndFilePStr, destPathAndFileCStr);
355         c2pstr(sourcePathAndFilePStr);
356         c2pstr(destPathAndFilePStr);
357         
358         do {
359                 // Open the source file
360                 sourceFile = fopen(sourcePathAndFileCStr,"rb");
361
362                 if (!sourceFile) {
363
364                         if (request_cd() == -1)
365                                 Error("Cannot load file <%s> from CD",filename);
366                 }
367
368         } while (!sourceFile);
369
370
371         // Get the time stamp from the source file
372         theSourcePigHFSParams.fileParam.ioCompletion    = nil;
373         theSourcePigHFSParams.fileParam.ioNamePtr               = sourcePathAndFilePStr;
374         theSourcePigHFSParams.fileParam.ioVRefNum               = cd_VRefNum;
375         theSourcePigHFSParams.fileParam.ioFDirIndex     = 0;
376         theSourcePigHFSParams.fileParam.ioDirID         = 0;
377         
378         theErr = PBHGetFInfo(&theSourcePigHFSParams, false);
379         if (theErr != noErr)
380         {
381                 // Error getting file time stamp!! Why? JTS
382                 Error("Can't get old file time stamp: <%s>\n", sourcePathAndFileCStr);
383         }
384         
385         // Copy the file over
386         // C Stuff......
387         
388         // Open the destination file
389         destFile = fopen(destPathAndFileCStr,"wb");
390         if (!destFile)
391         {
392                 Error("Cannot create file: <%s>\n", destPathAndFileCStr);
393         }
394         
395         // Copy bytes until the end of the source file
396         while (!feof(sourceFile))
397         {
398                 int bytes_read;
399                 int x;
400
401                 bytes_read = fread(buf,1,BUF_SIZE,sourceFile);
402                 if (ferror(sourceFile))
403                         Error("Cannot read from file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
404
405 // Assert is bogus              Assert(bytes_read == BUF_SIZE || feof(sourceFile));
406
407                 fwrite(buf,1,bytes_read,destFile);
408                 if (ferror(destFile))
409                         Error("Cannot write to file <%s>: %s",destPathAndFileCStr, strerror(errno));
410         }
411
412         // close the source/dest files
413         if (fclose(sourceFile))
414                 Error("Error closing file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
415         if (fclose(destFile))
416                 Error("Error closing file <%s>: %s", destPathAndFileCStr, strerror(errno));
417
418         // Get the current hfs data for the new file
419         theDestPigHFSParams.fileParam.ioCompletion      = nil;
420         theDestPigHFSParams.fileParam.ioNamePtr         = destPathAndFilePStr;
421         theDestPigHFSParams.fileParam.ioVRefNum         = 0;
422         theDestPigHFSParams.fileParam.ioFDirIndex       = 0;
423         theDestPigHFSParams.fileParam.ioDirID           = 0;
424         theErr = PBHGetFInfo(&theDestPigHFSParams, false);
425         if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
426         {
427                 // Error getting file time stamp!! Why? JTS
428                 Error("Can't get destination pig file information: <%s>\n", destPathAndFileCStr);
429         }
430
431         // Reset this data !!!!! or else the relative pathname won't work, could use just filename instead but, oh well.
432         theDestPigHFSParams.fileParam.ioNamePtr         = destPathAndFilePStr;
433         theDestPigHFSParams.fileParam.ioVRefNum         = 0;
434         theDestPigHFSParams.fileParam.ioFDirIndex       = 0;
435         theDestPigHFSParams.fileParam.ioDirID           = 0;
436
437         // Copy the time stamp from the source file info
438         theDestPigHFSParams.fileParam.ioFlCrDat = theSourcePigHFSParams.fileParam.ioFlCrDat;
439         theDestPigHFSParams.fileParam.ioFlMdDat = theSourcePigHFSParams.fileParam.ioFlMdDat;
440         theDestPigHFSParams.fileParam.ioFlFndrInfo.fdType = 'PGGY';
441         theDestPigHFSParams.fileParam.ioFlFndrInfo.fdCreator = 'DCT2';
442         
443         // Set the dest file's time stamp to the source file's time stamp values
444         theErr = PBHSetFInfo(&theDestPigHFSParams, false);
445
446         if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
447         {
448                 Error("Can't set destination pig file time stamp: <%s>\n", destPathAndFileCStr);
449         }
450
451         theErr = PBHGetFInfo(&theDestPigHFSParams, false);
452
453         return cfopen(destPathAndFileCStr, "rb");
454 }
455
456 #else   //PC Version of copy_pigfile_from_cd is below
457
458 //copies a pigfile from the CD to the current dir
459 //retuns file handle of new pig
460 CFILE *copy_pigfile_from_cd(char *filename)
461 {
462         char name[80];
463         FILEFINDSTRUCT find;
464         int ret;
465
466         return cfopen(filename, "rb");
467         show_boxed_message("Copying bitmap data from CD...");
468         gr_palette_load(gr_palette);    //I don't think this line is really needed
469
470         //First, delete all PIG files currently in the directory
471
472         if( !FileFindFirst( "*.pig", &find ) ) {
473                 do      {
474                         remove(find.name);
475                 } while( !FileFindNext( &find ) );
476                 FileFindClose();
477         }
478
479         //Now, copy over new pig
480
481         songs_stop_redbook();           //so we can read off the cd
482
483         //new code to unarj file
484         strcpy(name,CDROM_dir);
485         strcat(name,"descent2.sow");
486
487         do {
488 //              ret = unarj_specific_file(name,filename,filename);
489 // DPH:FIXME
490
491                 ret = !EXIT_SUCCESS;
492
493                 if (ret != EXIT_SUCCESS) {
494
495                         //delete file, so we don't leave partial file
496                         remove(filename);
497
498                         #ifndef MACINTOSH
499                         if (request_cd() == -1)
500                         #endif
501                                 //NOTE LINK TO ABOVE IF
502                                 Error("Cannot load file <%s> from CD",filename);
503                 }
504
505         } while (ret != EXIT_SUCCESS);
506
507         return cfopen(filename, "rb");
508 }
509
510 #endif // end of ifdef MAC around copy_pigfile_from_cd
511
512 //initialize a pigfile, reading headers
513 //returns the size of all the bitmap data
514 void piggy_init_pigfile(char *filename)
515 {
516         int i;
517         char temp_name[16];
518         char temp_name_read[16];
519         grs_bitmap temp_bitmap;
520         DiskBitmapHeader bmh;
521         int header_size, N_bitmaps, data_size, data_start;
522         #ifdef MACINTOSH
523         char name[255];         // filename + path for the mac
524         #endif
525
526         piggy_close_file();             //close old pig if still open
527
528         //rename pigfile for shareware
529         if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(filename))
530                 filename = DEFAULT_PIGFILE_SHAREWARE;
531
532         #ifndef MACINTOSH
533                 Piggy_fp = cfopen( filename, "rb" );
534         #else
535                 sprintf(name, ":Data:%s", filename);
536                 Piggy_fp = cfopen( name, "rb" );
537
538                 #ifdef SHAREWARE        // if we are in the shareware version, we must have the pig by now.
539                         if (Piggy_fp == NULL)
540                         {
541                                 Error("Cannot load required file <%s>",name);
542                         }
543                 #endif  // end of if def shareware
544
545         #endif
546
547         if (!Piggy_fp) {
548                 #ifdef EDITOR
549                         return;         //if editor, ok to not have pig, because we'll build one
550                 #else
551                         Piggy_fp = copy_pigfile_from_cd(filename);
552                 #endif
553         }
554
555         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
556                 int pig_id,pig_version;
557
558                 pig_id = cfile_read_int(Piggy_fp);
559                 pig_version = cfile_read_int(Piggy_fp);
560                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
561                         cfclose(Piggy_fp);              //out of date pig
562                         Piggy_fp = NULL;                        //..so pretend it's not here
563                 }
564         }
565
566         if (!Piggy_fp) {
567
568                 #ifdef EDITOR
569                         return;         //if editor, ok to not have pig, because we'll build one
570                 #else
571                         Error("Cannot load required file <%s>",filename);
572                 #endif
573         }
574
575         if (cfilelength(Piggy_fp) == 4929684) // mac version of d2demo.pig
576                 Gr_transparency_color = 0;
577
578         strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
579
580         N_bitmaps = cfile_read_int(Piggy_fp);
581
582         header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
583
584         data_start = header_size + cftell(Piggy_fp);
585
586         data_size = cfilelength(Piggy_fp) - data_start;
587
588         Num_bitmap_files = 1;
589
590         for (i=0; i<N_bitmaps; i++ )    {
591                 DiskBitmapHeader_read(&bmh, Piggy_fp);
592                 memcpy( temp_name_read, bmh.name, 8 );
593                 temp_name_read[8] = 0;
594                 if ( bmh.dflags & DBM_FLAG_ABM )        
595                         sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
596                 else
597                         strcpy( temp_name, temp_name_read );
598                 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
599                 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
600                 temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
601                 temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
602                 temp_bitmap.avg_color = bmh.avg_color;
603                 temp_bitmap.bm_data = Piggy_bitmap_cache_data;
604
605                 GameBitmapFlags[i+1] = 0;
606                 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_TRANSPARENT;
607                 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_SUPER_TRANSPARENT;
608                 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i+1] |= BM_FLAG_NO_LIGHTING;
609                 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i+1] |= BM_FLAG_RLE;
610                 if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i+1] |= BM_FLAG_RLE_BIG;
611
612                 GameBitmapOffset[i+1] = bmh.offset + data_start;
613                 Assert( (i+1) == Num_bitmap_files );
614                 piggy_register_bitmap( &temp_bitmap, temp_name, 1 );
615         }
616
617 #ifdef EDITOR
618         Piggy_bitmap_cache_size = data_size + (data_size/10);   //extra mem for new bitmaps
619         Assert( Piggy_bitmap_cache_size > 0 );
620 #else
621         Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
622         #ifdef MACINTOSH
623         if (piggy_low_memory)
624                 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
625         #endif
626 #endif
627         BitmapBits = d_malloc( Piggy_bitmap_cache_size );
628         if ( BitmapBits == NULL )
629                 Error( "Not enough memory to load bitmaps\n" );
630         Piggy_bitmap_cache_data = BitmapBits;
631         Piggy_bitmap_cache_next = 0;
632
633         #if defined(MACINTOSH) && defined(SHAREWARE)
634 //      load_exit_models();
635         #endif
636
637         Pigfile_initialized=1;
638 }
639
640 #define FILENAME_LEN 13
641 #define MAX_BITMAPS_PER_BRUSH 30
642
643 extern int compute_average_pixel(grs_bitmap *new);
644
645 //reads in a new pigfile (for new palette)
646 //returns the size of all the bitmap data
647 void piggy_new_pigfile(char *pigname)
648 {
649         int i;
650         char temp_name[16];
651         char temp_name_read[16];
652         grs_bitmap temp_bitmap;
653         DiskBitmapHeader bmh;
654         int header_size, N_bitmaps, data_size, data_start;
655         int must_rewrite_pig = 0;
656         #ifdef MACINTOSH
657         char name[255];
658         #endif
659
660         strlwr(pigname);
661
662         //rename pigfile for shareware
663         if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(pigname))
664                 pigname = DEFAULT_PIGFILE_SHAREWARE;
665
666         if (strnicmp(Current_pigfile,pigname,sizeof(Current_pigfile))==0)
667                 return;         //already have correct pig
668
669         if (!Pigfile_initialized) {                     //have we ever opened a pigfile?
670                 piggy_init_pigfile(pigname);            //..no, so do initialization stuff
671                 return;
672         }
673         else
674                 piggy_close_file();             //close old pig if still open
675
676         Piggy_bitmap_cache_next = 0;            //free up cache
677
678         strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
679
680         #ifndef MACINTOSH
681                 Piggy_fp = cfopen( pigname, "rb" );
682         #else
683                 sprintf(name, ":Data:%s", pigname);
684                 Piggy_fp = cfopen( name, "rb" );
685
686                 #ifdef SHAREWARE        // if we are in the shareware version, we must have the pig by now.
687                         if (Piggy_fp == NULL)
688                         {
689                                 Error("Cannot load required file <%s>",name);
690                         }
691                 #endif  // end of if def shareware
692         #endif
693
694         #ifndef EDITOR
695         if (!Piggy_fp)
696                 Piggy_fp = copy_pigfile_from_cd(pigname);
697         #endif
698
699         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
700                 int pig_id,pig_version;
701
702                 pig_id = cfile_read_int(Piggy_fp);
703                 pig_version = cfile_read_int(Piggy_fp);
704                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
705                         cfclose(Piggy_fp);              //out of date pig
706                         Piggy_fp = NULL;                        //..so pretend it's not here
707                 }
708         }
709
710         #ifndef EDITOR
711         if (!Piggy_fp) Error ("Piggy_fp not defined in piggy_new_pigfile.");
712         #endif
713
714         if (cfilelength(Piggy_fp) == 4929684) // mac version of d2demo.pig
715                 Gr_transparency_color = 0;
716
717         if (Piggy_fp) {
718
719                 N_bitmaps = cfile_read_int(Piggy_fp);
720         
721                 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
722         
723                 data_start = header_size + cftell(Piggy_fp);
724
725                 data_size = cfilelength(Piggy_fp) - data_start;
726         
727                 for (i=1; i<=N_bitmaps; i++ )   {
728                         DiskBitmapHeader_read(&bmh, Piggy_fp);
729                         memcpy( temp_name_read, bmh.name, 8 );
730                         temp_name_read[8] = 0;
731         
732                         if ( bmh.dflags & DBM_FLAG_ABM )        
733                                 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
734                         else
735                                 strcpy( temp_name, temp_name_read );
736         
737                         //Make sure name matches
738                         if (strcmp(temp_name,AllBitmaps[i].name)) {
739                                 //Int3();       //this pig is out of date.  Delete it
740                                 must_rewrite_pig=1;
741                         }
742         
743                         strcpy(AllBitmaps[i].name,temp_name);
744
745                         memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
746         
747                         temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
748                         temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
749                         temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
750                         temp_bitmap.avg_color = bmh.avg_color;
751                         temp_bitmap.bm_data = Piggy_bitmap_cache_data;
752
753                         GameBitmapFlags[i] = 0;
754
755                         if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_TRANSPARENT;
756                         if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_SUPER_TRANSPARENT;
757                         if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i] |= BM_FLAG_NO_LIGHTING;
758                         if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i] |= BM_FLAG_RLE;
759                         if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i] |= BM_FLAG_RLE_BIG;
760         
761                         GameBitmapOffset[i] = bmh.offset + data_start;
762         
763                         GameBitmaps[i] = temp_bitmap;
764                 }
765         }
766         else
767                 N_bitmaps = 0;          //no pigfile, so no bitmaps
768
769         #ifndef EDITOR
770
771         Assert(N_bitmaps == Num_bitmap_files-1);
772
773         #else
774
775         if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
776                 int size;
777
778                 //re-read the bitmaps that aren't in this pig
779
780                 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
781                         char *p;
782
783                         p = strchr(AllBitmaps[i].name,'#');
784
785                         if (p) {                //this is an ABM
786                                 char abmname[FILENAME_LEN];
787                                 int fnum;
788                                 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
789                                 int iff_error;          //reference parm to avoid warning message
790                                 ubyte newpal[768];
791                                 char basename[FILENAME_LEN];
792                                 int nframes;
793                         
794                                 strcpy(basename,AllBitmaps[i].name);
795                                 basename[p-AllBitmaps[i].name] = 0;             //cut off "#nn" part
796                                 
797                                 sprintf( abmname, "%s.abm", basename );
798
799                                 iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
800
801                                 if (iff_error != IFF_NO_ERROR)  {
802                                         mprintf((1,"File %s - IFF error: %s",abmname,iff_errormsg(iff_error)));
803                                         Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
804                                 }
805                         
806                                 for (fnum=0;fnum<nframes; fnum++)       {
807                                         char tempname[20];
808                                         int SuperX;
809
810                                         sprintf( tempname, "%s#%d", basename, fnum );
811
812                                         //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
813                                         SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
814                                         //above makes assumption that supertransparent color is 254
815
816                                         if ( iff_has_transparency )
817                                                 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
818                                         else
819                                                 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
820
821                                         bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
822
823 #ifdef EDITOR
824                                         if ( FindArg("-macdata") )
825                                                 swap_0_255( bm[fnum] );
826 #endif
827                                         if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
828
829                                         if (bm[fnum]->bm_flags & BM_FLAG_RLE)
830                                                 size = *((int *) bm[fnum]->bm_data);
831                                         else
832                                                 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
833
834                                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
835                                         d_free(bm[fnum]->bm_data);
836                                         bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
837                                         Piggy_bitmap_cache_next += size;
838
839                                         GameBitmaps[i+fnum] = *bm[fnum];
840
841                                         // -- mprintf( (0, "U" ));
842                                         d_free( bm[fnum] );
843                                 }
844
845                                 i += nframes-1;         //filled in multiple bitmaps
846                         }
847                         else {          //this is a BBM
848
849                                 grs_bitmap * new;
850                                 ubyte newpal[256*3];
851                                 int iff_error;
852                                 char bbmname[FILENAME_LEN];
853                                 int SuperX;
854
855                                 MALLOC( new, grs_bitmap, 1 );
856
857                                 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
858                                 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
859
860                                 new->bm_handle=0;
861                                 if (iff_error != IFF_NO_ERROR)          {
862                                         mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)));
863                                         Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
864                                 }
865
866                                 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
867                                 //above makes assumption that supertransparent color is 254
868
869                                 if ( iff_has_transparency )
870                                         gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
871                                 else
872                                         gr_remap_bitmap_good( new, newpal, -1, SuperX );
873
874                                 new->avg_color = compute_average_pixel(new);
875
876 #ifdef EDITOR
877                                 if ( FindArg("-macdata") )
878                                         swap_0_255( new );
879 #endif
880                                 if ( !BigPig )  gr_bitmap_rle_compress( new );
881
882                                 if (new->bm_flags & BM_FLAG_RLE)
883                                         size = *((int *) new->bm_data);
884                                 else
885                                         size = new->bm_w * new->bm_h;
886
887                                 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size);
888                                 d_free(new->bm_data);
889                                 new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
890                                 Piggy_bitmap_cache_next += size;
891
892                                 GameBitmaps[i] = *new;
893         
894                                 d_free( new );
895
896                                 // -- mprintf( (0, "U" ));
897                         }
898                 }
899
900                 //@@Dont' do these things which are done when writing
901                 //@@for (i=0; i < Num_bitmap_files; i++ )       {
902                 //@@    bitmap_index bi;
903                 //@@    bi.index = i;
904                 //@@    PIGGY_PAGE_IN( bi );
905                 //@@}
906                 //@@
907                 //@@piggy_close_file();
908
909                 piggy_write_pigfile(pigname);
910
911                 Current_pigfile[0] = 0;                 //say no pig, to force reload
912
913                 piggy_new_pigfile(pigname);             //read in just-generated pig
914
915
916         }
917         #endif  //ifdef EDITOR
918
919 }
920
921 ubyte bogus_data[64*64];
922 grs_bitmap bogus_bitmap;
923 ubyte bogus_bitmap_initialized=0;
924 digi_sound bogus_sound;
925
926 #define HAMFILE_ID              MAKE_SIG('!','M','A','H') //HAM!
927 #define HAMFILE_VERSION 3
928 //version 1 -> 2:  save marker_model_num
929 //version 2 -> 3:  removed sound files
930
931 #define SNDFILE_ID              MAKE_SIG('D','N','S','D') //DSND
932 #define SNDFILE_VERSION 1
933
934 int read_hamfile()
935 {
936         CFILE * ham_fp = NULL;
937         int ham_id;
938         int sound_offset = 0;
939         #ifdef MACINTOSH
940         char name[255];
941         #endif
942
943         #ifndef MACINTOSH
944         ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
945         #else
946         sprintf(name, ":Data:%s", DEFAULT_HAMFILE );
947         ham_fp = cfopen( name, "rb" );
948         #endif
949
950         if (ham_fp == NULL) {
951                 Must_write_hamfile = 1;
952                 return 0;
953         }
954
955         //make sure ham is valid type file & is up-to-date
956         ham_id = cfile_read_int(ham_fp);
957         Piggy_hamfile_version = cfile_read_int(ham_fp);
958         if (ham_id != HAMFILE_ID)
959                 Error("Cannot open ham file %s\n", DEFAULT_HAMFILE);
960 #if 0
961         if (ham_id != HAMFILE_ID || Piggy_hamfile_version != HAMFILE_VERSION) {
962                 Must_write_hamfile = 1;
963                 cfclose(ham_fp);                                                //out of date ham
964                 return 0;
965         }
966 #endif
967
968         if (Piggy_hamfile_version < 3) // hamfile contains sound info
969                 sound_offset = cfile_read_int(ham_fp);
970
971         #ifndef EDITOR
972         {
973                 //int i;
974
975                 bm_read_all(ham_fp);
976                 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
977                 // no swap here?
978                 //for (i = 0; i < MAX_BITMAP_FILES; i++) {
979                         //GameBitmapXlat[i] = INTEL_SHORT(GameBitmapXlat[i]);
980                         //printf("GameBitmapXlat[%d] = %d\n", i, GameBitmapXlat[i]);
981                 //}
982         }
983         #endif
984
985         if (Piggy_hamfile_version < 3) {
986                 int N_sounds;
987                 int sound_start;
988                 int header_size;
989                 int i;
990                 DiskSoundHeader sndh;
991                 digi_sound temp_sound;
992                 char temp_name_read[16];
993                 int sbytes = 0;
994
995                 cfseek(ham_fp, sound_offset, SEEK_SET);
996                 N_sounds = cfile_read_int(ham_fp);
997
998                 sound_start = cftell(ham_fp);
999
1000                 header_size = N_sounds * DISKSOUNDHEADER_SIZE;
1001
1002                 //Read sounds
1003
1004                 for (i=0; i<N_sounds; i++ ) {
1005                         DiskSoundHeader_read(&sndh, ham_fp);
1006                         temp_sound.length = sndh.length;
1007                         temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1008                         SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1009                         memcpy( temp_name_read, sndh.name, 8 );
1010                         temp_name_read[8] = 0;
1011                         piggy_register_sound( &temp_sound, temp_name_read, 1 );
1012 #ifdef MACINTOSH
1013                         if (piggy_is_needed(i))
1014 #endif          // note link to if.
1015                                 sbytes += sndh.length;
1016                         //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1017                 }
1018
1019                 SoundBits = d_malloc( sbytes + 16 );
1020                 if ( SoundBits == NULL )
1021                         Error( "Not enough memory to load sounds\n" );
1022
1023                 mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1024
1025                 //      piggy_read_sounds(ham_fp);
1026
1027         }
1028
1029         cfclose(ham_fp);
1030
1031         return 1;
1032
1033 }
1034
1035 int read_sndfile()
1036 {
1037         CFILE * snd_fp = NULL;
1038         int snd_id,snd_version;
1039         int N_sounds;
1040         int sound_start;
1041         int header_size;
1042         int i,size, length;
1043         DiskSoundHeader sndh;
1044         digi_sound temp_sound;
1045         char temp_name_read[16];
1046         int sbytes = 0;
1047         #ifdef MACINTOSH
1048         char name[255];
1049         #endif
1050
1051         #ifndef MACINTOSH
1052         snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
1053         #else
1054         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1055         snd_fp = cfopen( name, "rb");
1056         #endif
1057         
1058         if (snd_fp == NULL)
1059                 return 0;
1060
1061         //make sure soundfile is valid type file & is up-to-date
1062         snd_id = cfile_read_int(snd_fp);
1063         snd_version = cfile_read_int(snd_fp);
1064         if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) {
1065                 cfclose(snd_fp);                                                //out of date sound file
1066                 return 0;
1067         }
1068
1069         N_sounds = cfile_read_int(snd_fp);
1070
1071         sound_start = cftell(snd_fp);
1072         size = cfilelength(snd_fp) - sound_start;
1073         length = size;
1074         mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
1075
1076         header_size = N_sounds*sizeof(DiskSoundHeader);
1077
1078         //Read sounds
1079
1080         for (i=0; i<N_sounds; i++ ) {
1081                 DiskSoundHeader_read(&sndh, snd_fp);
1082                 //size -= sizeof(DiskSoundHeader);
1083                 temp_sound.length = sndh.length;
1084                 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1085                 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1086                 memcpy( temp_name_read, sndh.name, 8 );
1087                 temp_name_read[8] = 0;
1088                 piggy_register_sound( &temp_sound, temp_name_read, 1 );
1089                 #ifdef MACINTOSH
1090                 if (piggy_is_needed(i))
1091                 #endif          // note link to if.
1092                 sbytes += sndh.length;
1093                 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1094         }
1095
1096         SoundBits = d_malloc( sbytes + 16 );
1097         if ( SoundBits == NULL )
1098                 Error( "Not enough memory to load sounds\n" );
1099
1100         mprintf(( 0, "\nBitmaps: %d KB   Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1101
1102 //      piggy_read_sounds(snd_fp);
1103
1104         cfclose(snd_fp);
1105
1106         return 1;
1107 }
1108
1109 int piggy_init(void)
1110 {
1111         int ham_ok=0,snd_ok=0;
1112         int i;
1113
1114         hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
1115         hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
1116
1117         for (i=0; i<MAX_SOUND_FILES; i++ )      {
1118                 GameSounds[i].length = 0;
1119                 GameSounds[i].data = NULL;
1120                 SoundOffset[i] = 0;
1121         }
1122
1123         for (i=0; i<MAX_BITMAP_FILES; i++ )     
1124                 GameBitmapXlat[i] = i;
1125
1126         if ( !bogus_bitmap_initialized )        {
1127                 int i;
1128                 ubyte c;
1129                 bogus_bitmap_initialized = 1;
1130                 memset( &bogus_bitmap, 0, sizeof(grs_bitmap) );
1131                 bogus_bitmap.bm_w = bogus_bitmap.bm_h = bogus_bitmap.bm_rowsize = 64;
1132                 bogus_bitmap.bm_data = bogus_data;
1133                 c = gr_find_closest_color( 0, 0, 63 );
1134                 for (i=0; i<4096; i++ ) bogus_data[i] = c;
1135                 c = gr_find_closest_color( 63, 0, 0 );
1136                 // Make a big red X !
1137                 for (i=0; i<64; i++ )   {
1138                         bogus_data[i*64+i] = c;
1139                         bogus_data[i*64+(63-i)] = c;
1140                 }
1141                 piggy_register_bitmap( &bogus_bitmap, "bogus", 1 );
1142                 bogus_sound.length = 64*64;
1143                 bogus_sound.data = bogus_data;
1144                 GameBitmapOffset[0] = 0;
1145         }
1146
1147         if ( FindArg( "-bigpig" ))
1148                 BigPig = 1;
1149
1150         if ( FindArg( "-lowmem" ))
1151                 piggy_low_memory = 1;
1152
1153         if ( FindArg( "-nolowmem" ))
1154                 piggy_low_memory = 0;
1155
1156         if (piggy_low_memory)
1157                 digi_lomem = 1;
1158
1159         WIN(DDGRLOCK(dd_grd_curcanv));
1160                 gr_set_curfont( SMALL_FONT );
1161                 gr_set_fontcolor(gr_find_closest_color_current( 20, 20, 20 ),-1 );
1162                 gr_printf( 0x8000, grd_curcanv->cv_h-20, "%s...", TXT_LOADING_DATA );
1163         WIN(DDGRUNLOCK(dd_grd_curcanv));
1164
1165         #ifdef EDITOR
1166         piggy_init_pigfile(DEFAULT_PIGFILE);
1167         #endif
1168
1169         snd_ok = ham_ok = read_hamfile();
1170
1171         if (Piggy_hamfile_version >= 3)
1172                 snd_ok = read_sndfile();
1173
1174         atexit(piggy_close);
1175
1176         mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1177         return (ham_ok && snd_ok);               //read ok
1178 }
1179
1180 int piggy_is_needed(int soundnum)
1181 {
1182         int i;
1183
1184         if ( !digi_lomem ) return 1;
1185
1186         for (i=0; i<MAX_SOUNDS; i++ )   {
1187                 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1188                         return 1;
1189         }
1190         return 0;
1191 }
1192
1193
1194 void piggy_read_sounds(void)
1195 {
1196         CFILE * fp = NULL;
1197         ubyte * ptr;
1198         int i, sbytes;
1199         #ifdef MACINTOSH
1200         char name[255];
1201         #endif
1202
1203         ptr = SoundBits;
1204         sbytes = 0;
1205
1206         #ifndef MACINTOSH
1207         fp = cfopen( DEFAULT_SNDFILE, "rb" );
1208         #else
1209         sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1210         fp = cfopen( name, "rb");
1211         #endif
1212
1213         if (fp == NULL)
1214                 return;
1215
1216         for (i=0; i<Num_sound_files; i++ )      {
1217                 digi_sound *snd = &GameSounds[i];
1218
1219                 if ( SoundOffset[i] > 0 )       {
1220                         if ( piggy_is_needed(i) )       {
1221                                 cfseek( fp, SoundOffset[i], SEEK_SET );
1222
1223                                 // Read in the sound data!!!
1224                                 snd->data = ptr;
1225                                 ptr += snd->length;
1226                                 sbytes += snd->length;
1227                                 cfread( snd->data, snd->length, 1, fp );
1228                         }
1229                         else
1230                                 snd->data = (ubyte *) -1;
1231                 }
1232         }
1233
1234         cfclose(fp);
1235
1236         mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1237
1238 }
1239
1240
1241 extern int descent_critical_error;
1242 extern unsigned descent_critical_deverror;
1243 extern unsigned descent_critical_errcode;
1244
1245 char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \
1246 "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \
1247 "Read fault", "General Failure" };
1248
1249 void piggy_critical_error()
1250 {
1251         grs_canvas * save_canv;
1252         grs_font * save_font;
1253         int i;
1254         save_canv = grd_curcanv;
1255         save_font = grd_curcanv->cv_font;
1256         gr_palette_load( gr_palette );
1257         i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A'  );
1258         if ( i == 1 )
1259                 exit(1);
1260         gr_set_current_canvas(save_canv);
1261         grd_curcanv->cv_font = save_font;
1262 }
1263
1264 void piggy_bitmap_page_in( bitmap_index bitmap )
1265 {
1266         grs_bitmap * bmp;
1267         int i,org_i,temp;
1268
1269         org_i = 0;
1270
1271         i = bitmap.index;
1272         Assert( i >= 0 );
1273         Assert( i < MAX_BITMAP_FILES );
1274         Assert( i < Num_bitmap_files );
1275         Assert( Piggy_bitmap_cache_size > 0 );
1276
1277         if ( i < 1 ) return;
1278         if ( i >= MAX_BITMAP_FILES ) return;
1279         if ( i >= Num_bitmap_files ) return;
1280
1281         if ( GameBitmapOffset[i] == 0 ) return;         // A read-from-disk bitmap!!!
1282
1283         if ( piggy_low_memory ) {
1284                 org_i = i;
1285                 i = GameBitmapXlat[i];          // Xlat for low-memory settings!
1286         }
1287
1288         bmp = &GameBitmaps[i];
1289
1290         if ( bmp->bm_flags & BM_FLAG_PAGED_OUT )        {
1291                 stop_time();
1292
1293         ReDoIt:
1294                 descent_critical_error = 0;
1295                 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1296                 if ( descent_critical_error )   {
1297                         piggy_critical_error();
1298                         goto ReDoIt;
1299                 }
1300
1301                 bmp->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
1302                 bmp->bm_flags = GameBitmapFlags[i];
1303
1304                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1305                         int zsize = 0;
1306                         descent_critical_error = 0;
1307                         zsize = cfile_read_int(Piggy_fp);
1308                         if ( descent_critical_error )   {
1309                                 piggy_critical_error();
1310                                 goto ReDoIt;
1311                         }
1312
1313                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1314                         //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
1315                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1316                                 Int3();
1317                                 piggy_bitmap_page_out_all();
1318                                 goto ReDoIt;
1319                         }
1320                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], &zsize, sizeof(int) );
1321                         Piggy_bitmap_cache_next += sizeof(int);
1322                         descent_critical_error = 0;
1323                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, zsize-4, Piggy_fp );
1324                         if ( descent_critical_error )   {
1325                                 piggy_critical_error();
1326                                 goto ReDoIt;
1327                         }
1328                         Piggy_bitmap_cache_next += zsize-4;
1329
1330                         if (Gr_transparency_color == 0)
1331                                 rle_swap_0_255( bmp );
1332
1333                 } else {
1334                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1335                         Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
1336                         if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1337                                 piggy_bitmap_page_out_all();
1338                                 goto ReDoIt;
1339                         }
1340                         descent_critical_error = 0;
1341                         temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1342                         if ( descent_critical_error )   {
1343                                 piggy_critical_error();
1344                                 goto ReDoIt;
1345                         }
1346                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1347
1348                         if (Gr_transparency_color == 0)
1349                                 swap_0_255( bmp );
1350
1351                 }
1352
1353
1354
1355                 //@@if ( bmp->bm_selector ) {
1356                 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1357                 //@@    if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1358                 //@@            Error( "Error modifying selector base in piggy.c\n" );
1359                 //@@#endif
1360                 //@@}
1361
1362                 start_time();
1363         }
1364
1365         if ( piggy_low_memory ) {
1366                 if ( org_i != i )
1367                         GameBitmaps[org_i] = GameBitmaps[i];
1368         }
1369
1370 //@@Removed from John's code:
1371 //@@#ifndef WINDOWS
1372 //@@    if ( bmp->bm_selector ) {
1373 //@@            if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1374 //@@                    Error( "Error modifying selector base in piggy.c\n" );
1375 //@@    }
1376 //@@#endif
1377
1378 }
1379
1380 void piggy_bitmap_page_out_all()
1381 {
1382         int i;
1383         
1384         Piggy_bitmap_cache_next = 0;
1385
1386         piggy_page_flushed++;
1387
1388         texmerge_flush();
1389         rle_cache_flush();
1390
1391         for (i=0; i<Num_bitmap_files; i++ )             {
1392                 if ( GameBitmapOffset[i] > 0 )  {       // Don't page out bitmaps read from disk!!!
1393                         GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1394                         GameBitmaps[i].bm_data = Piggy_bitmap_cache_data;
1395                 }
1396         }
1397
1398         mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1399 }
1400
1401 void piggy_load_level_data()
1402 {
1403         piggy_bitmap_page_out_all();
1404         paging_touch_all();
1405 }
1406
1407 #ifdef EDITOR
1408
1409 void change_filename_ext( char *dest, char *src, char *ext );
1410
1411 void piggy_write_pigfile(char *filename)
1412 {
1413         FILE *pig_fp;
1414         int bitmap_data_start,data_offset;
1415         DiskBitmapHeader bmh;
1416         int org_offset;
1417         char subst_name[32];
1418         int i;
1419         FILE *fp1,*fp2;
1420         char tname[FILENAME_LEN];
1421
1422         // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1423         for (i=0; i < Num_bitmap_files; i++ )   {
1424                 bitmap_index bi;
1425                 bi.index = i;
1426                 PIGGY_PAGE_IN( bi );
1427         }
1428         // -- mprintf( (0, "\n" ));
1429
1430         piggy_close_file();
1431
1432         // -- mprintf( (0, "Creating %s...",filename ));
1433
1434         pig_fp = fopen( filename, "wb" );       //open PIG file
1435         Assert( pig_fp!=NULL );
1436
1437         write_int(PIGFILE_ID,pig_fp);
1438         write_int(PIGFILE_VERSION,pig_fp);
1439
1440         Num_bitmap_files--;
1441         fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1442         Num_bitmap_files++;
1443
1444         bitmap_data_start = ftell(pig_fp);
1445         bitmap_data_start += (Num_bitmap_files-1)*DISKBITMAPHEADER_SIZE; 
1446         data_offset = bitmap_data_start;
1447
1448         change_filename_ext(tname,filename,"lst");
1449         fp1 = fopen( tname, "wt" );
1450         change_filename_ext(tname,filename,"all");
1451         fp2 = fopen( tname, "wt" );
1452
1453         for (i=1; i < Num_bitmap_files; i++ )   {
1454                 int *size;
1455                 grs_bitmap *bmp;
1456
1457                 {               
1458                         char * p, *p1;
1459                         p = strchr(AllBitmaps[i].name,'#');
1460                         if (p)  {
1461                                 int n;
1462                                 p1 = p; p1++; 
1463                                 n = atoi(p1);
1464                                 *p = 0;
1465                                 if (fp2 && n==0)
1466                                         fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1467                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1468                                 Assert( n <= 63 );
1469                                 bmh.dflags = DBM_FLAG_ABM + n;
1470                                 *p = '#';
1471                         }else {
1472                                 if (fp2)
1473                                         fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1474                                 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1475                                 bmh.dflags = 0;
1476                         }
1477                 }
1478                 bmp = &GameBitmaps[i];
1479
1480                 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1481
1482                 if (fp1)
1483                         fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1484                 org_offset = ftell(pig_fp);
1485                 bmh.offset = data_offset - bitmap_data_start;
1486                 fseek( pig_fp, data_offset, SEEK_SET );
1487
1488                 if ( bmp->bm_flags & BM_FLAG_RLE )      {
1489                         size = (int *)bmp->bm_data;
1490                         fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1491                         data_offset += *size;
1492                         if (fp1)
1493                                 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1494                 } else {
1495                         fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1496                         data_offset += bmp->bm_rowsize * bmp->bm_h;
1497                         if (fp1)
1498                                 fprintf( fp1, ".\n" );
1499                 }
1500                 fseek( pig_fp, org_offset, SEEK_SET );
1501                 Assert( GameBitmaps[i].bm_w < 4096 );
1502                 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1503                 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1504                 Assert( GameBitmaps[i].bm_h < 4096 );
1505                 bmh.height = GameBitmaps[i].bm_h;
1506                 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1507                 bmh.flags = GameBitmaps[i].bm_flags;
1508                 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name ))    {
1509                         bitmap_index other_bitmap;
1510                         other_bitmap = piggy_find_bitmap( subst_name );
1511                         GameBitmapXlat[i] = other_bitmap.index;
1512                         bmh.flags |= BM_FLAG_PAGED_OUT;
1513                         //mprintf(( 0, "Skipping bitmap %d\n", i ));
1514                         //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1515                 } else  {
1516                         bmh.flags &= ~BM_FLAG_PAGED_OUT;
1517                 }
1518                 bmh.avg_color=GameBitmaps[i].avg_color;
1519                 fwrite( &bmh, DISKBITMAPHEADER_SIZE, 1, pig_fp );                    // Mark as a bitmap
1520         }
1521
1522         fclose(pig_fp);
1523
1524         mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1525         fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1526
1527         fclose(fp1);
1528         fclose(fp2);
1529
1530 }
1531
1532 static void write_int(int i,FILE *file)
1533 {
1534         if (fwrite( &i, sizeof(i), 1, file) != 1)
1535                 Error( "Error reading int in gamesave.c" );
1536
1537 }
1538
1539 void piggy_dump_all()
1540 {
1541         int i, xlat_offset;
1542         FILE * ham_fp;
1543         int org_offset,data_offset=0;
1544         DiskSoundHeader sndh;
1545         int sound_data_start=0;
1546         FILE *fp1,*fp2;
1547
1548         #ifdef NO_DUMP_SOUNDS
1549         Num_sound_files = 0;
1550         Num_sound_files_new = 0;
1551         #endif
1552
1553         if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1554                 return;
1555
1556         fp1 = fopen( "ham.lst", "wt" );
1557         fp2 = fopen( "ham.all", "wt" );
1558
1559         if (Must_write_hamfile || Num_bitmap_files_new) {
1560
1561                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1562         
1563                 ham_fp = fopen( DEFAULT_HAMFILE, "wb" );                       //open HAM file
1564                 Assert( ham_fp!=NULL );
1565         
1566                 write_int(HAMFILE_ID,ham_fp);
1567                 write_int(HAMFILE_VERSION,ham_fp);
1568         
1569                 bm_write_all(ham_fp);
1570                 xlat_offset = ftell(ham_fp);
1571                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1572                 //Dump bitmaps
1573         
1574                 if (Num_bitmap_files_new)
1575                         piggy_write_pigfile(DEFAULT_PIGFILE);
1576         
1577                 //free up memeory used by new bitmaps
1578                 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1579                         d_free(GameBitmaps[i].bm_data);
1580         
1581                 //next thing must be done after pig written
1582                 fseek( ham_fp, xlat_offset, SEEK_SET );
1583                 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1584         
1585                 fclose(ham_fp);
1586                 mprintf( (0, "\n" ));
1587         }
1588         
1589         if (Num_sound_files_new) {
1590
1591                 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1592                 // Now dump sound file
1593                 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1594                 Assert( ham_fp!=NULL );
1595         
1596                 write_int(SNDFILE_ID,ham_fp);
1597                 write_int(SNDFILE_VERSION,ham_fp);
1598
1599                 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1600         
1601                 mprintf( (0, "\nDumping sounds..." ));
1602         
1603                 sound_data_start = ftell(ham_fp);
1604                 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1605                 data_offset = sound_data_start;
1606         
1607                 for (i=0; i < Num_sound_files; i++ )    {
1608                         digi_sound *snd;
1609         
1610                         snd = &GameSounds[i];
1611                         strcpy( sndh.name, AllSounds[i].name );
1612                         sndh.length = GameSounds[i].length;
1613                         sndh.offset = data_offset - sound_data_start;
1614         
1615                         org_offset = ftell(ham_fp);
1616                         fseek( ham_fp, data_offset, SEEK_SET );
1617         
1618                         sndh.data_length = GameSounds[i].length;
1619                         fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1620                         data_offset += snd->length;
1621                         fseek( ham_fp, org_offset, SEEK_SET );
1622                         fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp );                    // Mark as a bitmap
1623         
1624                         fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1625                         fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1626                 }
1627
1628                 fclose(ham_fp);
1629                 mprintf( (0, "\n" ));
1630         }
1631
1632         fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1633         mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1634         fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1635
1636         fclose(fp1);
1637         fclose(fp2);
1638
1639         // Never allow the game to run after building ham.
1640         exit(0);
1641 }
1642
1643 #endif
1644
1645 void piggy_close()
1646 {
1647         piggy_close_file();
1648
1649         if (BitmapBits)
1650                 d_free(BitmapBits);
1651
1652         if ( SoundBits )
1653                 d_free( SoundBits );
1654
1655         hashtable_free( &AllBitmapsNames );
1656         hashtable_free( &AllDigiSndNames );
1657
1658 }
1659
1660 int piggy_does_bitmap_exist_slow( char * name )
1661 {
1662         int i;
1663
1664         for (i=0; i<Num_bitmap_files; i++ )     {
1665                 if ( !strcmp( AllBitmaps[i].name, name) )
1666                         return 1;
1667         }
1668         return 0;
1669 }
1670
1671
1672 #define NUM_GAUGE_BITMAPS 23
1673 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1674         "gauge01", "gauge01b",
1675         "gauge02", "gauge02b",
1676         "gauge06", "gauge06b",
1677         "targ01", "targ01b",
1678         "targ02", "targ02b", 
1679         "targ03", "targ03b",
1680         "targ04", "targ04b",
1681         "targ05", "targ05b",
1682         "targ06", "targ06b",
1683         "gauge18", "gauge18b",
1684         "gauss1", "helix1",
1685         "phoenix1"
1686 };
1687
1688
1689 int piggy_is_gauge_bitmap( char * base_name )
1690 {
1691         int i;
1692         for (i=0; i<NUM_GAUGE_BITMAPS; i++ )    {
1693                 if ( !stricmp( base_name, gauge_bitmap_names[i] ))      
1694                         return 1;
1695         }
1696
1697         return 0;       
1698 }
1699
1700 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1701 {
1702         int frame;
1703         char * p;
1704         char base_name[ 16 ];
1705         
1706         strcpy( subst_name, name );
1707         p = strchr( subst_name, '#' );
1708         if ( p )        {
1709                 frame = atoi( &p[1] );
1710                 *p = 0;
1711                 strcpy( base_name, subst_name );
1712                 if ( !piggy_is_gauge_bitmap( base_name ))       {
1713                         sprintf( subst_name, "%s#%d", base_name, frame+1 );
1714                         if ( piggy_does_bitmap_exist_slow( subst_name )  )      {
1715                                 if ( frame & 1 ) {
1716                                         sprintf( subst_name, "%s#%d", base_name, frame-1 );
1717                                         return 1;
1718                                 }
1719                         }
1720                 }
1721         }
1722         strcpy( subst_name, name );
1723         return 0;
1724 }
1725
1726
1727
1728 #ifdef WINDOWS
1729 //      New Windows stuff
1730
1731 //      windows bitmap page in
1732 //              Page in a bitmap, if ddraw, then page it into a ddsurface in 
1733 //              'video' memory.  if that fails, page it in normally.
1734
1735 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1736 {
1737 }
1738
1739
1740 //      Essential when switching video modes!
1741
1742 void piggy_bitmap_page_out_all_w()
1743 {
1744 }
1745
1746 #endif
1747
1748 #ifndef FAST_FILE_IO
1749 /*
1750  * reads a bitmap_index structure from a CFILE
1751  */
1752 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
1753 {
1754         bi->index = cfile_read_short(fp);
1755 }
1756
1757 /*
1758  * reads n bitmap_index structs from a CFILE
1759  */
1760 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
1761 {
1762         int i;
1763
1764         for (i = 0; i < n; i++)
1765                 bi[i].index = cfile_read_short(fp);
1766         return i;
1767 }
1768
1769 /*
1770  * reads a DiskBitmapHeader structure from a CFILE
1771  */
1772 void DiskBitmapHeader_read(DiskBitmapHeader *dbh, CFILE *fp)
1773 {
1774         cfread(dbh->name, 8, 1, fp);
1775         dbh->dflags = cfile_read_byte(fp);
1776         dbh->width = cfile_read_byte(fp);
1777         dbh->height = cfile_read_byte(fp);
1778         dbh->wh_extra = cfile_read_byte(fp);
1779         dbh->flags = cfile_read_byte(fp);
1780         dbh->avg_color = cfile_read_byte(fp);
1781         dbh->offset = cfile_read_int(fp);
1782 }
1783
1784 /*
1785  * reads a DiskSoundHeader structure from a CFILE
1786  */
1787 void DiskSoundHeader_read(DiskSoundHeader *dsh, CFILE *fp)
1788 {
1789         cfread(dsh->name, 8, 1, fp);
1790         dsh->length = cfile_read_int(fp);
1791         dsh->data_length = cfile_read_int(fp);
1792         dsh->offset = cfile_read_int(fp);
1793 }
1794 #endif