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