2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
19 static char rcsid[] = "$Id: piggy.c,v 1.14 2002-08-02 04:57:19 btb Exp $";
58 #include <Strings.h> // MacOS Toolbox header
63 //#define NO_DUMP_SOUNDS 1 //if set, dump bitmaps but not sounds
65 #define DEFAULT_PIGFILE_REGISTERED "groupa.pig"
66 #define DEFAULT_PIGFILE_SHAREWARE "d2demo.pig"
70 #define DEFAULT_HAMFILE "d2demo.ham"
71 #define DEFAULT_PIGFILE DEFAULT_PIGFILE_SHAREWARE
72 #define DEFAULT_SNDFILE DEFAULT_HAMFILE //"descent2.s11"
74 #define DEFAULT_HAMFILE "descent2.ham"
75 #define DEFAULT_PIGFILE DEFAULT_PIGFILE_REGISTERED
76 #define DEFAULT_SNDFILE ((digi_sample_rate==SAMPLE_RATE_22K)?"descent2.s22":"descent2.s11")
77 #endif // end of ifdef SHAREWARE
79 ubyte *BitmapBits = NULL;
80 ubyte *SoundBits = NULL;
82 typedef struct BitmapFile {
86 typedef struct SoundFile {
90 hashtable AllBitmapsNames;
91 hashtable AllDigiSndNames;
93 int Num_bitmap_files = 0;
94 int Num_sound_files = 0;
96 digi_sound GameSounds[MAX_SOUND_FILES];
97 int SoundOffset[MAX_SOUND_FILES];
98 grs_bitmap GameBitmaps[MAX_BITMAP_FILES];
100 alias alias_list[MAX_ALIASES];
103 int Must_write_hamfile = 0;
104 int Num_bitmap_files_new = 0;
105 int Num_sound_files_new = 0;
106 BitmapFile AllBitmaps[ MAX_BITMAP_FILES ];
107 static SoundFile AllSounds[ MAX_SOUND_FILES ];
109 int piggy_low_memory = 0;
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];
118 #define PIGGY_BUFFER_SIZE (2400*1024)
121 #define PIGGY_SMALL_BUFFER_SIZE (1400*1024) // size of buffer when piggy_low_memory is set
124 #undef PIGGY_BUFFER_SIZE
125 #undef PIGGY_SMALL_BUFFER_SIZE
127 #define PIGGY_BUFFER_SIZE (2000*1024)
128 #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024)
133 int piggy_page_flushed = 0;
135 #define DBM_FLAG_ABM 64
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);
146 int piggy_is_substitutable_bitmap( char * name, char * subst_name );
149 void piggy_write_pigfile(char *filename);
150 static void write_int(int i,FILE *file);
152 void swap_0_255(grs_bitmap *bmp)
156 for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) {
157 if(bmp->bm_data[i] == 0)
158 bmp->bm_data[i] = 255;
159 else if (bmp->bm_data[i] == 255)
165 bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file )
168 Assert( Num_bitmap_files < MAX_BITMAP_FILES );
170 temp.index = Num_bitmap_files;
174 if ( FindArg("-macdata") )
177 if ( !BigPig ) gr_bitmap_rle_compress( bmp );
178 Num_bitmap_files_new++;
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;
185 GameBitmapOffset[Num_bitmap_files] = 0;
186 GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags;
193 int piggy_register_sound( digi_sound * snd, char * name, int in_file )
197 Assert( Num_sound_files < MAX_SOUND_FILES );
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;
203 SoundOffset[Num_sound_files] = 0;
209 Num_sound_files_new++;
215 bitmap_index piggy_find_bitmap( char * name )
223 if ((t=strchr(name,'#'))!=NULL)
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 );
236 name=alias_list[i].file_name;
243 i = hashtable_search( &AllBitmapsNames, name );
252 int piggy_find_sound( char * name )
256 i = hashtable_search( &AllDigiSndNames, name );
264 CFILE * Piggy_fp = NULL;
266 #define FILENAME_LEN 13
268 char Current_pigfile[FILENAME_LEN] = "";
270 void piggy_close_file()
275 Current_pigfile[0] = 0;
279 int Pigfile_initialized=0;
281 #define PIGFILE_ID MAKE_SIG('G','I','P','P') //PPIG
282 #define PIGFILE_VERSION 2
284 extern char CDROM_dir[];
286 int request_cd(void);
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
296 char sourcePathAndFileCStr[255] = "";
297 char destPathAndFileCStr[255] = "";
299 FILE* sourceFile = NULL;
300 FILE* destFile = NULL;
301 const int BUF_SIZE = 4096;
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] = "";
313 getcwd(oldDirCStr, 255);
315 show_boxed_message("Copying bitmap data from CD...");
316 gr_palette_load(gr_palette); //I don't think this line is really needed
319 //First, delete all PIG files currently in the directory
320 if( !FileFindFirst( "*.pig", &find ) )
325 } while( !FileFindNext( &find ) );
331 //Now, copy over new pig
332 songs_stop_redbook(); //so we can read off the cd
334 // make the source path "<cd volume>:Data:filename.pig"
335 //MWA ConvertCToPStr(filename, pigfileNamePStr);
337 //MWA ConcatPStr(sourcePathAndFilePStr, "\pDescent II:Data:"); // volume ID is cd_VRefNum
338 //MWA ConcatPStr(sourcePathAndFilePStr, pigfileNamePStr);
341 strcpy(sourcePathAndFileCStr, "Descent II:Data:");
342 strcat(sourcePathAndFileCStr, filename);
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);
350 strcpy(destPathAndFileCStr, ":Data:");
351 strcat(destPathAndFileCStr, filename);
353 strcpy(sourcePathAndFilePStr, sourcePathAndFileCStr);
354 strcpy(destPathAndFilePStr, destPathAndFileCStr);
355 c2pstr(sourcePathAndFilePStr);
356 c2pstr(destPathAndFilePStr);
359 // Open the source file
360 sourceFile = fopen(sourcePathAndFileCStr,"rb");
364 if (request_cd() == -1)
365 Error("Cannot load file <%s> from CD",filename);
368 } while (!sourceFile);
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;
378 theErr = PBHGetFInfo(&theSourcePigHFSParams, false);
381 // Error getting file time stamp!! Why? JTS
382 Error("Can't get old file time stamp: <%s>\n", sourcePathAndFileCStr);
385 // Copy the file over
388 // Open the destination file
389 destFile = fopen(destPathAndFileCStr,"wb");
392 Error("Cannot create file: <%s>\n", destPathAndFileCStr);
395 // Copy bytes until the end of the source file
396 while (!feof(sourceFile))
401 bytes_read = fread(buf,1,BUF_SIZE,sourceFile);
402 if (ferror(sourceFile))
403 Error("Cannot read from file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
405 // Assert is bogus Assert(bytes_read == BUF_SIZE || feof(sourceFile));
407 fwrite(buf,1,bytes_read,destFile);
408 if (ferror(destFile))
409 Error("Cannot write to file <%s>: %s",destPathAndFileCStr, strerror(errno));
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));
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))
427 // Error getting file time stamp!! Why? JTS
428 Error("Can't get destination pig file information: <%s>\n", destPathAndFileCStr);
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;
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';
443 // Set the dest file's time stamp to the source file's time stamp values
444 theErr = PBHSetFInfo(&theDestPigHFSParams, false);
446 if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
448 Error("Can't set destination pig file time stamp: <%s>\n", destPathAndFileCStr);
451 theErr = PBHGetFInfo(&theDestPigHFSParams, false);
453 return cfopen(destPathAndFileCStr, "rb");
456 #else //PC Version of copy_pigfile_from_cd is below
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)
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
470 //First, delete all PIG files currently in the directory
472 if( !FileFindFirst( "*.pig", &find ) ) {
475 } while( !FileFindNext( &find ) );
479 //Now, copy over new pig
481 songs_stop_redbook(); //so we can read off the cd
483 //new code to unarj file
484 strcpy(name,CDROM_dir);
485 strcat(name,"descent2.sow");
488 // ret = unarj_specific_file(name,filename,filename);
493 if (ret != EXIT_SUCCESS) {
495 //delete file, so we don't leave partial file
499 if (request_cd() == -1)
501 //NOTE LINK TO ABOVE IF
502 Error("Cannot load file <%s> from CD",filename);
505 } while (ret != EXIT_SUCCESS);
507 return cfopen(filename, "rb");
510 #endif // end of ifdef MAC around copy_pigfile_from_cd
512 //initialize a pigfile, reading headers
513 //returns the size of all the bitmap data
514 void piggy_init_pigfile(char *filename)
518 char temp_name_read[16];
519 grs_bitmap temp_bitmap;
520 DiskBitmapHeader bmh;
521 int header_size, N_bitmaps, data_size, data_start;
523 char name[255]; // filename + path for the mac
526 piggy_close_file(); //close old pig if still open
528 #ifdef SHAREWARE //rename pigfile for shareware
529 if (stricmp(filename,DEFAULT_PIGFILE_REGISTERED)==0)
530 filename = DEFAULT_PIGFILE_SHAREWARE;
534 Piggy_fp = cfopen( filename, "rb" );
536 sprintf(name, ":Data:%s", filename);
537 Piggy_fp = cfopen( name, "rb" );
539 #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now.
540 if (Piggy_fp == NULL)
542 Error("Cannot load required file <%s>",name);
544 #endif // end of if def shareware
550 return; //if editor, ok to not have pig, because we'll build one
552 Piggy_fp = copy_pigfile_from_cd(filename);
556 if (Piggy_fp) { //make sure pig is valid type file & is up-to-date
557 int pig_id,pig_version;
559 pig_id = cfile_read_int(Piggy_fp);
560 pig_version = cfile_read_int(Piggy_fp);
561 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
562 cfclose(Piggy_fp); //out of date pig
563 Piggy_fp = NULL; //..so pretend it's not here
570 return; //if editor, ok to not have pig, because we'll build one
572 Error("Cannot load required file <%s>",filename);
576 strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
578 N_bitmaps = cfile_read_int(Piggy_fp);
580 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
582 data_start = header_size + cftell(Piggy_fp);
584 data_size = cfilelength(Piggy_fp) - data_start;
586 Num_bitmap_files = 1;
588 for (i=0; i<N_bitmaps; i++ ) {
589 DiskBitmapHeader_read(&bmh, Piggy_fp);
590 memcpy( temp_name_read, bmh.name, 8 );
591 temp_name_read[8] = 0;
592 if ( bmh.dflags & DBM_FLAG_ABM )
593 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
595 strcpy( temp_name, temp_name_read );
596 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
597 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
598 temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
599 temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
600 temp_bitmap.avg_color = bmh.avg_color;
601 temp_bitmap.bm_data = Piggy_bitmap_cache_data;
603 GameBitmapFlags[i+1] = 0;
604 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_TRANSPARENT;
605 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_SUPER_TRANSPARENT;
606 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i+1] |= BM_FLAG_NO_LIGHTING;
607 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i+1] |= BM_FLAG_RLE;
608 if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i+1] |= BM_FLAG_RLE_BIG;
610 GameBitmapOffset[i+1] = bmh.offset + data_start;
611 Assert( (i+1) == Num_bitmap_files );
612 piggy_register_bitmap( &temp_bitmap, temp_name, 1 );
616 Piggy_bitmap_cache_size = data_size + (data_size/10); //extra mem for new bitmaps
617 Assert( Piggy_bitmap_cache_size > 0 );
619 Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
621 if (piggy_low_memory)
622 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
625 BitmapBits = d_malloc( Piggy_bitmap_cache_size );
626 if ( BitmapBits == NULL )
627 Error( "Not enough memory to load bitmaps\n" );
628 Piggy_bitmap_cache_data = BitmapBits;
629 Piggy_bitmap_cache_next = 0;
631 #if defined(MACINTOSH) && defined(SHAREWARE)
632 // load_exit_models();
635 Pigfile_initialized=1;
638 #define FILENAME_LEN 13
639 #define MAX_BITMAPS_PER_BRUSH 30
641 extern int compute_average_pixel(grs_bitmap *new);
643 //reads in a new pigfile (for new palette)
644 //returns the size of all the bitmap data
645 void piggy_new_pigfile(char *pigname)
649 char temp_name_read[16];
650 grs_bitmap temp_bitmap;
651 DiskBitmapHeader bmh;
652 int header_size, N_bitmaps, data_size, data_start;
653 int must_rewrite_pig = 0;
660 #ifdef SHAREWARE //rename pigfile for shareware
661 if (stricmp(pigname,DEFAULT_PIGFILE_REGISTERED)==0)
662 pigname = DEFAULT_PIGFILE_SHAREWARE;
665 if (strnicmp(Current_pigfile,pigname,sizeof(Current_pigfile))==0)
666 return; //already have correct pig
668 if (!Pigfile_initialized) { //have we ever opened a pigfile?
669 piggy_init_pigfile(pigname); //..no, so do initialization stuff
673 piggy_close_file(); //close old pig if still open
675 Piggy_bitmap_cache_next = 0; //free up cache
677 strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
680 Piggy_fp = cfopen( pigname, "rb" );
682 sprintf(name, ":Data:%s", pigname);
683 Piggy_fp = cfopen( name, "rb" );
685 #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now.
686 if (Piggy_fp == NULL)
688 Error("Cannot load required file <%s>",name);
690 #endif // end of if def shareware
695 Piggy_fp = copy_pigfile_from_cd(pigname);
698 if (Piggy_fp) { //make sure pig is valid type file & is up-to-date
699 int pig_id,pig_version;
701 pig_id = cfile_read_int(Piggy_fp);
702 pig_version = cfile_read_int(Piggy_fp);
703 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
704 cfclose(Piggy_fp); //out of date pig
705 Piggy_fp = NULL; //..so pretend it's not here
710 if (!Piggy_fp) Error ("Piggy_fp not defined in piggy_new_pigfile.");
715 N_bitmaps = cfile_read_int(Piggy_fp);
717 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
719 data_start = header_size + cftell(Piggy_fp);
721 data_size = cfilelength(Piggy_fp) - data_start;
723 for (i=1; i<=N_bitmaps; i++ ) {
724 DiskBitmapHeader_read(&bmh, Piggy_fp);
725 memcpy( temp_name_read, bmh.name, 8 );
726 temp_name_read[8] = 0;
728 if ( bmh.dflags & DBM_FLAG_ABM )
729 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
731 strcpy( temp_name, temp_name_read );
733 //Make sure name matches
734 if (strcmp(temp_name,AllBitmaps[i].name)) {
735 //Int3(); //this pig is out of date. Delete it
739 strcpy(AllBitmaps[i].name,temp_name);
741 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
743 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = bmh.width + ((short) (bmh.wh_extra&0x0f)<<8);
744 temp_bitmap.bm_h = bmh.height + ((short) (bmh.wh_extra&0xf0)<<4);
745 temp_bitmap.bm_flags = BM_FLAG_PAGED_OUT;
746 temp_bitmap.avg_color = bmh.avg_color;
747 temp_bitmap.bm_data = Piggy_bitmap_cache_data;
749 GameBitmapFlags[i] = 0;
751 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_TRANSPARENT;
752 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i] |= BM_FLAG_SUPER_TRANSPARENT;
753 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i] |= BM_FLAG_NO_LIGHTING;
754 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i] |= BM_FLAG_RLE;
755 if ( bmh.flags & BM_FLAG_RLE_BIG ) GameBitmapFlags[i] |= BM_FLAG_RLE_BIG;
757 GameBitmapOffset[i] = bmh.offset + data_start;
759 GameBitmaps[i] = temp_bitmap;
763 N_bitmaps = 0; //no pigfile, so no bitmaps
767 Assert(N_bitmaps == Num_bitmap_files-1);
771 if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
774 //re-read the bitmaps that aren't in this pig
776 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
779 p = strchr(AllBitmaps[i].name,'#');
781 if (p) { //this is an ABM
782 char abmname[FILENAME_LEN];
784 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
785 int iff_error; //reference parm to avoid warning message
787 char basename[FILENAME_LEN];
790 strcpy(basename,AllBitmaps[i].name);
791 basename[p-AllBitmaps[i].name] = 0; //cut off "#nn" part
793 sprintf( abmname, "%s.abm", basename );
795 iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
797 if (iff_error != IFF_NO_ERROR) {
798 mprintf((1,"File %s - IFF error: %s",abmname,iff_errormsg(iff_error)));
799 Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
802 for (fnum=0;fnum<nframes; fnum++) {
806 sprintf( tempname, "%s#%d", basename, fnum );
808 //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
809 SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
810 //above makes assumption that supertransparent color is 254
812 if ( iff_has_transparency )
813 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
815 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
817 bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
820 if ( FindArg("-macdata") )
821 swap_0_255( bm[fnum] );
823 if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
825 if (bm[fnum]->bm_flags & BM_FLAG_RLE)
826 size = *((int *) bm[fnum]->bm_data);
828 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
830 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
831 d_free(bm[fnum]->bm_data);
832 bm[fnum]->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
833 Piggy_bitmap_cache_next += size;
835 GameBitmaps[i+fnum] = *bm[fnum];
837 // -- mprintf( (0, "U" ));
841 i += nframes-1; //filled in multiple bitmaps
843 else { //this is a BBM
848 char bbmname[FILENAME_LEN];
851 MALLOC( new, grs_bitmap, 1 );
853 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
854 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
857 if (iff_error != IFF_NO_ERROR) {
858 mprintf((1, "File %s - IFF error: %s",bbmname,iff_errormsg(iff_error)));
859 Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
862 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
863 //above makes assumption that supertransparent color is 254
865 if ( iff_has_transparency )
866 gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
868 gr_remap_bitmap_good( new, newpal, -1, SuperX );
870 new->avg_color = compute_average_pixel(new);
873 if ( FindArg("-macdata") )
876 if ( !BigPig ) gr_bitmap_rle_compress( new );
878 if (new->bm_flags & BM_FLAG_RLE)
879 size = *((int *) new->bm_data);
881 size = new->bm_w * new->bm_h;
883 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],new->bm_data,size);
884 d_free(new->bm_data);
885 new->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
886 Piggy_bitmap_cache_next += size;
888 GameBitmaps[i] = *new;
892 // -- mprintf( (0, "U" ));
896 //@@Dont' do these things which are done when writing
897 //@@for (i=0; i < Num_bitmap_files; i++ ) {
898 //@@ bitmap_index bi;
900 //@@ PIGGY_PAGE_IN( bi );
903 //@@piggy_close_file();
905 piggy_write_pigfile(pigname);
907 Current_pigfile[0] = 0; //say no pig, to force reload
909 piggy_new_pigfile(pigname); //read in just-generated pig
913 #endif //ifdef EDITOR
917 ubyte bogus_data[64*64];
918 grs_bitmap bogus_bitmap;
919 ubyte bogus_bitmap_initialized=0;
920 digi_sound bogus_sound;
922 #define HAMFILE_ID MAKE_SIG('!','M','A','H') //HAM!
924 #define HAMFILE_VERSION 2
926 #define HAMFILE_VERSION 3
928 //version 1 -> 2: save marker_model_num
929 //version 2 -> 3: removed sound files
931 #define SNDFILE_ID MAKE_SIG('D','N','S','D') //DSND
932 #define SNDFILE_VERSION 1
936 CFILE * ham_fp = NULL;
937 int ham_id,ham_version;
938 int sound_offset = 0;
944 ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
946 sprintf(name, ":Data:%s", DEFAULT_HAMFILE );
947 ham_fp = cfopen( name, "rb" );
950 if (ham_fp == NULL) {
951 Must_write_hamfile = 1;
955 //make sure ham is valid type file & is up-to-date
956 ham_id = cfile_read_int(ham_fp);
957 ham_version = cfile_read_int(ham_fp);
958 if (ham_id != HAMFILE_ID || ham_version != HAMFILE_VERSION) {
959 Must_write_hamfile = 1;
960 cfclose(ham_fp); //out of date ham
964 if (ham_version < 3) // hamfile contains sound info
965 sound_offset = cfile_read_int(ham_fp);
971 bm_read_all(ham_fp, ham_version);
972 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
974 //for (i = 0; i < MAX_BITMAP_FILES; i++) {
975 //GameBitmapXlat[i] = INTEL_SHORT(GameBitmapXlat[i]);
976 //printf("GameBitmapXlat[%d] = %d\n", i, GameBitmapXlat[i]);
981 if (ham_version < 3) {
986 DiskSoundHeader sndh;
987 digi_sound temp_sound;
988 char temp_name_read[16];
991 cfseek(ham_fp, sound_offset, SEEK_SET);
992 N_sounds = cfile_read_int(ham_fp);
994 sound_start = cftell(ham_fp);
996 header_size = N_sounds * DISKSOUNDHEADER_SIZE;
1000 for (i=0; i<N_sounds; i++ ) {
1001 DiskSoundHeader_read(&sndh, ham_fp);
1002 temp_sound.length = sndh.length;
1003 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1004 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1005 memcpy( temp_name_read, sndh.name, 8 );
1006 temp_name_read[8] = 0;
1007 piggy_register_sound( &temp_sound, temp_name_read, 1 );
1009 if (piggy_is_needed(i))
1010 #endif // note link to if.
1011 sbytes += sndh.length;
1012 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1015 SoundBits = d_malloc( sbytes + 16 );
1016 if ( SoundBits == NULL )
1017 Error( "Not enough memory to load sounds\n" );
1019 mprintf(( 0, "\nBitmaps: %d KB Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1021 // piggy_read_sounds(ham_fp);
1033 CFILE * snd_fp = NULL;
1034 int snd_id,snd_version;
1039 DiskSoundHeader sndh;
1040 digi_sound temp_sound;
1041 char temp_name_read[16];
1048 snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
1050 sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1051 snd_fp = cfopen( name, "rb");
1057 //make sure soundfile is valid type file & is up-to-date
1058 snd_id = cfile_read_int(snd_fp);
1059 snd_version = cfile_read_int(snd_fp);
1060 if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) {
1061 cfclose(snd_fp); //out of date sound file
1065 N_sounds = cfile_read_int(snd_fp);
1067 sound_start = cftell(snd_fp);
1068 size = cfilelength(snd_fp) - sound_start;
1070 mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
1072 header_size = N_sounds*sizeof(DiskSoundHeader);
1076 for (i=0; i<N_sounds; i++ ) {
1077 DiskSoundHeader_read(&sndh, snd_fp);
1078 //size -= sizeof(DiskSoundHeader);
1079 temp_sound.length = sndh.length;
1080 temp_sound.data = (ubyte *)(sndh.offset + header_size + sound_start);
1081 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
1082 memcpy( temp_name_read, sndh.name, 8 );
1083 temp_name_read[8] = 0;
1084 piggy_register_sound( &temp_sound, temp_name_read, 1 );
1086 if (piggy_is_needed(i))
1087 #endif // note link to if.
1088 sbytes += sndh.length;
1089 //mprintf(( 0, "%d bytes of sound\n", sbytes ));
1092 SoundBits = d_malloc( sbytes + 16 );
1093 if ( SoundBits == NULL )
1094 Error( "Not enough memory to load sounds\n" );
1096 mprintf(( 0, "\nBitmaps: %d KB Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1098 // piggy_read_sounds(snd_fp);
1105 int piggy_init(void)
1107 int ham_ok=0,snd_ok=0;
1110 hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
1111 hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
1113 for (i=0; i<MAX_SOUND_FILES; i++ ) {
1114 GameSounds[i].length = 0;
1115 GameSounds[i].data = NULL;
1119 for (i=0; i<MAX_BITMAP_FILES; i++ )
1120 GameBitmapXlat[i] = i;
1122 if ( !bogus_bitmap_initialized ) {
1125 bogus_bitmap_initialized = 1;
1126 memset( &bogus_bitmap, 0, sizeof(grs_bitmap) );
1127 bogus_bitmap.bm_w = bogus_bitmap.bm_h = bogus_bitmap.bm_rowsize = 64;
1128 bogus_bitmap.bm_data = bogus_data;
1129 c = gr_find_closest_color( 0, 0, 63 );
1130 for (i=0; i<4096; i++ ) bogus_data[i] = c;
1131 c = gr_find_closest_color( 63, 0, 0 );
1132 // Make a big red X !
1133 for (i=0; i<64; i++ ) {
1134 bogus_data[i*64+i] = c;
1135 bogus_data[i*64+(63-i)] = c;
1137 piggy_register_bitmap( &bogus_bitmap, "bogus", 1 );
1138 bogus_sound.length = 64*64;
1139 bogus_sound.data = bogus_data;
1140 GameBitmapOffset[0] = 0;
1143 if ( FindArg( "-bigpig" ))
1146 if ( FindArg( "-lowmem" ))
1147 piggy_low_memory = 1;
1149 if ( FindArg( "-nolowmem" ))
1150 piggy_low_memory = 0;
1152 if (piggy_low_memory)
1155 WIN(DDGRLOCK(dd_grd_curcanv));
1156 gr_set_curfont( SMALL_FONT );
1157 gr_set_fontcolor(gr_find_closest_color_current( 20, 20, 20 ),-1 );
1158 gr_printf( 0x8000, grd_curcanv->cv_h-20, "%s...", TXT_LOADING_DATA );
1159 WIN(DDGRUNLOCK(dd_grd_curcanv));
1162 piggy_init_pigfile(DEFAULT_PIGFILE);
1166 ham_ok = read_hamfile();
1167 snd_ok = read_sndfile();
1169 snd_ok = ham_ok = read_hamfile();
1172 atexit(piggy_close);
1174 mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1175 return (ham_ok && snd_ok); //read ok
1178 int piggy_is_needed(int soundnum)
1182 if ( !digi_lomem ) return 1;
1184 for (i=0; i<MAX_SOUNDS; i++ ) {
1185 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1192 void piggy_read_sounds(void)
1205 fp = cfopen( DEFAULT_SNDFILE, "rb" );
1207 sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1208 fp = cfopen( name, "rb");
1214 for (i=0; i<Num_sound_files; i++ ) {
1215 digi_sound *snd = &GameSounds[i];
1217 if ( SoundOffset[i] > 0 ) {
1218 if ( piggy_is_needed(i) ) {
1219 cfseek( fp, SoundOffset[i], SEEK_SET );
1221 // Read in the sound data!!!
1224 sbytes += snd->length;
1225 cfread( snd->data, snd->length, 1, fp );
1228 snd->data = (ubyte *) -1;
1234 mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1239 extern int descent_critical_error;
1240 extern unsigned descent_critical_deverror;
1241 extern unsigned descent_critical_errcode;
1243 char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", \
1244 "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", \
1245 "Read fault", "General Failure" };
1247 void piggy_critical_error()
1249 grs_canvas * save_canv;
1250 grs_font * save_font;
1252 save_canv = grd_curcanv;
1253 save_font = grd_curcanv->cv_font;
1254 gr_palette_load( gr_palette );
1255 i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A' );
1258 gr_set_current_canvas(save_canv);
1259 grd_curcanv->cv_font = save_font;
1262 void piggy_bitmap_page_in( bitmap_index bitmap )
1271 Assert( i < MAX_BITMAP_FILES );
1272 Assert( i < Num_bitmap_files );
1273 Assert( Piggy_bitmap_cache_size > 0 );
1275 if ( i < 1 ) return;
1276 if ( i >= MAX_BITMAP_FILES ) return;
1277 if ( i >= Num_bitmap_files ) return;
1279 if ( GameBitmapOffset[i] == 0 ) return; // A read-from-disk bitmap!!!
1281 if ( piggy_low_memory ) {
1283 i = GameBitmapXlat[i]; // Xlat for low-memory settings!
1286 bmp = &GameBitmaps[i];
1288 if ( bmp->bm_flags & BM_FLAG_PAGED_OUT ) {
1292 descent_critical_error = 0;
1293 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1294 if ( descent_critical_error ) {
1295 piggy_critical_error();
1299 bmp->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
1300 bmp->bm_flags = GameBitmapFlags[i];
1302 if ( bmp->bm_flags & BM_FLAG_RLE ) {
1304 descent_critical_error = 0;
1305 zsize = cfile_read_int(Piggy_fp);
1306 if ( descent_critical_error ) {
1307 piggy_critical_error();
1311 // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1312 //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
1313 if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
1315 piggy_bitmap_page_out_all();
1318 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], &zsize, sizeof(int) );
1319 Piggy_bitmap_cache_next += sizeof(int);
1320 descent_critical_error = 0;
1321 temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, zsize-4, Piggy_fp );
1322 if ( descent_critical_error ) {
1323 piggy_critical_error();
1326 Piggy_bitmap_cache_next += zsize-4;
1328 // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1329 Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
1330 if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1331 piggy_bitmap_page_out_all();
1334 descent_critical_error = 0;
1335 temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1336 if ( descent_critical_error ) {
1337 piggy_critical_error();
1340 Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1343 //@@if ( bmp->bm_selector ) {
1344 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1345 //@@ if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1346 //@@ Error( "Error modifying selector base in piggy.c\n" );
1353 if ( piggy_low_memory ) {
1355 GameBitmaps[org_i] = GameBitmaps[i];
1358 //@@Removed from John's code:
1360 //@@ if ( bmp->bm_selector ) {
1361 //@@ if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1362 //@@ Error( "Error modifying selector base in piggy.c\n" );
1368 void piggy_bitmap_page_out_all()
1372 Piggy_bitmap_cache_next = 0;
1374 piggy_page_flushed++;
1379 for (i=0; i<Num_bitmap_files; i++ ) {
1380 if ( GameBitmapOffset[i] > 0 ) { // Don't page out bitmaps read from disk!!!
1381 GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1382 GameBitmaps[i].bm_data = Piggy_bitmap_cache_data;
1386 mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1389 void piggy_load_level_data()
1391 piggy_bitmap_page_out_all();
1397 void change_filename_ext( char *dest, char *src, char *ext );
1399 void piggy_write_pigfile(char *filename)
1402 int bitmap_data_start,data_offset;
1403 DiskBitmapHeader bmh;
1405 char subst_name[32];
1408 char tname[FILENAME_LEN];
1410 // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1411 for (i=0; i < Num_bitmap_files; i++ ) {
1414 PIGGY_PAGE_IN( bi );
1416 // -- mprintf( (0, "\n" ));
1420 // -- mprintf( (0, "Creating %s...",filename ));
1422 pig_fp = fopen( filename, "wb" ); //open PIG file
1423 Assert( pig_fp!=NULL );
1425 write_int(PIGFILE_ID,pig_fp);
1426 write_int(PIGFILE_VERSION,pig_fp);
1429 fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1432 bitmap_data_start = ftell(pig_fp);
1433 bitmap_data_start += (Num_bitmap_files-1)*DISKBITMAPHEADER_SIZE;
1434 data_offset = bitmap_data_start;
1436 change_filename_ext(tname,filename,"lst");
1437 fp1 = fopen( tname, "wt" );
1438 change_filename_ext(tname,filename,"all");
1439 fp2 = fopen( tname, "wt" );
1441 for (i=1; i < Num_bitmap_files; i++ ) {
1447 p = strchr(AllBitmaps[i].name,'#');
1454 fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1455 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1457 bmh.dflags = DBM_FLAG_ABM + n;
1461 fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1462 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1466 bmp = &GameBitmaps[i];
1468 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1471 fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1472 org_offset = ftell(pig_fp);
1473 bmh.offset = data_offset - bitmap_data_start;
1474 fseek( pig_fp, data_offset, SEEK_SET );
1476 if ( bmp->bm_flags & BM_FLAG_RLE ) {
1477 size = (int *)bmp->bm_data;
1478 fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1479 data_offset += *size;
1481 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1483 fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1484 data_offset += bmp->bm_rowsize * bmp->bm_h;
1486 fprintf( fp1, ".\n" );
1488 fseek( pig_fp, org_offset, SEEK_SET );
1489 Assert( GameBitmaps[i].bm_w < 4096 );
1490 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1491 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1492 Assert( GameBitmaps[i].bm_h < 4096 );
1493 bmh.height = GameBitmaps[i].bm_h;
1494 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1495 bmh.flags = GameBitmaps[i].bm_flags;
1496 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name )) {
1497 bitmap_index other_bitmap;
1498 other_bitmap = piggy_find_bitmap( subst_name );
1499 GameBitmapXlat[i] = other_bitmap.index;
1500 bmh.flags |= BM_FLAG_PAGED_OUT;
1501 //mprintf(( 0, "Skipping bitmap %d\n", i ));
1502 //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1504 bmh.flags &= ~BM_FLAG_PAGED_OUT;
1506 bmh.avg_color=GameBitmaps[i].avg_color;
1507 fwrite( &bmh, DISKBITMAPHEADER_SIZE, 1, pig_fp ); // Mark as a bitmap
1512 mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1513 fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1520 static void write_int(int i,FILE *file)
1522 if (fwrite( &i, sizeof(i), 1, file) != 1)
1523 Error( "Error reading int in gamesave.c" );
1527 void piggy_dump_all()
1531 int org_offset,data_offset=0;
1532 DiskSoundHeader sndh;
1533 int sound_data_start=0;
1536 #ifdef NO_DUMP_SOUNDS
1537 Num_sound_files = 0;
1538 Num_sound_files_new = 0;
1541 if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1544 fp1 = fopen( "ham.lst", "wt" );
1545 fp2 = fopen( "ham.all", "wt" );
1547 if (Must_write_hamfile || Num_bitmap_files_new) {
1549 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1551 ham_fp = fopen( DEFAULT_HAMFILE, "wb" ); //open HAM file
1552 Assert( ham_fp!=NULL );
1554 write_int(HAMFILE_ID,ham_fp);
1555 write_int(HAMFILE_VERSION,ham_fp);
1557 bm_write_all(ham_fp);
1558 xlat_offset = ftell(ham_fp);
1559 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1562 if (Num_bitmap_files_new)
1563 piggy_write_pigfile(DEFAULT_PIGFILE);
1565 //free up memeory used by new bitmaps
1566 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1567 d_free(GameBitmaps[i].bm_data);
1569 //next thing must be done after pig written
1570 fseek( ham_fp, xlat_offset, SEEK_SET );
1571 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1574 mprintf( (0, "\n" ));
1577 if (Num_sound_files_new) {
1579 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1580 // Now dump sound file
1581 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1582 Assert( ham_fp!=NULL );
1584 write_int(SNDFILE_ID,ham_fp);
1585 write_int(SNDFILE_VERSION,ham_fp);
1587 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1589 mprintf( (0, "\nDumping sounds..." ));
1591 sound_data_start = ftell(ham_fp);
1592 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1593 data_offset = sound_data_start;
1595 for (i=0; i < Num_sound_files; i++ ) {
1598 snd = &GameSounds[i];
1599 strcpy( sndh.name, AllSounds[i].name );
1600 sndh.length = GameSounds[i].length;
1601 sndh.offset = data_offset - sound_data_start;
1603 org_offset = ftell(ham_fp);
1604 fseek( ham_fp, data_offset, SEEK_SET );
1606 sndh.data_length = GameSounds[i].length;
1607 fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1608 data_offset += snd->length;
1609 fseek( ham_fp, org_offset, SEEK_SET );
1610 fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp ); // Mark as a bitmap
1612 fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1613 fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1617 mprintf( (0, "\n" ));
1620 fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1621 mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1622 fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1627 // Never allow the game to run after building ham.
1641 d_free( SoundBits );
1643 hashtable_free( &AllBitmapsNames );
1644 hashtable_free( &AllDigiSndNames );
1648 int piggy_does_bitmap_exist_slow( char * name )
1652 for (i=0; i<Num_bitmap_files; i++ ) {
1653 if ( !strcmp( AllBitmaps[i].name, name) )
1660 #define NUM_GAUGE_BITMAPS 23
1661 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1662 "gauge01", "gauge01b",
1663 "gauge02", "gauge02b",
1664 "gauge06", "gauge06b",
1665 "targ01", "targ01b",
1666 "targ02", "targ02b",
1667 "targ03", "targ03b",
1668 "targ04", "targ04b",
1669 "targ05", "targ05b",
1670 "targ06", "targ06b",
1671 "gauge18", "gauge18b",
1677 int piggy_is_gauge_bitmap( char * base_name )
1680 for (i=0; i<NUM_GAUGE_BITMAPS; i++ ) {
1681 if ( !stricmp( base_name, gauge_bitmap_names[i] ))
1688 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1692 char base_name[ 16 ];
1694 strcpy( subst_name, name );
1695 p = strchr( subst_name, '#' );
1697 frame = atoi( &p[1] );
1699 strcpy( base_name, subst_name );
1700 if ( !piggy_is_gauge_bitmap( base_name )) {
1701 sprintf( subst_name, "%s#%d", base_name, frame+1 );
1702 if ( piggy_does_bitmap_exist_slow( subst_name ) ) {
1704 sprintf( subst_name, "%s#%d", base_name, frame-1 );
1710 strcpy( subst_name, name );
1717 // New Windows stuff
1719 // windows bitmap page in
1720 // Page in a bitmap, if ddraw, then page it into a ddsurface in
1721 // 'video' memory. if that fails, page it in normally.
1723 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1728 // Essential when switching video modes!
1730 void piggy_bitmap_page_out_all_w()
1736 #ifndef FAST_FILE_IO
1738 * reads a bitmap_index structure from a CFILE
1740 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
1742 bi->index = cfile_read_short(fp);
1746 * reads n bitmap_index structs from a CFILE
1748 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
1752 for (i = 0; i < n; i++)
1753 bi[i].index = cfile_read_short(fp);
1758 * reads a DiskBitmapHeader structure from a CFILE
1760 void DiskBitmapHeader_read(DiskBitmapHeader *dbh, CFILE *fp)
1762 cfread(dbh->name, 8, 1, fp);
1763 dbh->dflags = cfile_read_byte(fp);
1764 dbh->width = cfile_read_byte(fp);
1765 dbh->height = cfile_read_byte(fp);
1766 dbh->wh_extra = cfile_read_byte(fp);
1767 dbh->flags = cfile_read_byte(fp);
1768 dbh->avg_color = cfile_read_byte(fp);
1769 dbh->offset = cfile_read_int(fp);
1773 * reads a DiskSoundHeader structure from a CFILE
1775 void DiskSoundHeader_read(DiskSoundHeader *dsh, CFILE *fp)
1777 cfread(dsh->name, 8, 1, fp);
1778 dsh->length = cfile_read_int(fp);
1779 dsh->data_length = cfile_read_int(fp);
1780 dsh->offset = cfile_read_int(fp);