1 /* $Id: piggy.c,v 1.17 2002-08-15 08:53:11 btb Exp $ */
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.
20 static char rcsid[] = "$Id: piggy.c,v 1.17 2002-08-15 08:53:11 btb Exp $";
59 #include <Strings.h> // MacOS Toolbox header
64 //#define NO_DUMP_SOUNDS 1 //if set, dump bitmaps but not sounds
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"
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")
75 ubyte *BitmapBits = NULL;
76 ubyte *SoundBits = NULL;
78 typedef struct BitmapFile {
82 typedef struct SoundFile {
86 hashtable AllBitmapsNames;
87 hashtable AllDigiSndNames;
89 int Num_bitmap_files = 0;
90 int Num_sound_files = 0;
92 digi_sound GameSounds[MAX_SOUND_FILES];
93 int SoundOffset[MAX_SOUND_FILES];
94 grs_bitmap GameBitmaps[MAX_BITMAP_FILES];
96 alias alias_list[MAX_ALIASES];
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 ];
105 int Piggy_hamfile_version = 0;
107 int piggy_low_memory = 0;
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];
116 #define PIGGY_BUFFER_SIZE (2400*1024)
119 #define PIGGY_SMALL_BUFFER_SIZE (1400*1024) // size of buffer when piggy_low_memory is set
122 #undef PIGGY_BUFFER_SIZE
123 #undef PIGGY_SMALL_BUFFER_SIZE
125 #define PIGGY_BUFFER_SIZE (2000*1024)
126 #define PIGGY_SMALL_BUFFER_SIZE (1100 * 1024)
131 int piggy_page_flushed = 0;
133 #define DBM_FLAG_ABM 64
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);
144 int piggy_is_substitutable_bitmap( char * name, char * subst_name );
147 void piggy_write_pigfile(char *filename);
148 static void write_int(int i,FILE *file);
151 void swap_0_255(grs_bitmap *bmp)
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)
163 bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file )
166 Assert( Num_bitmap_files < MAX_BITMAP_FILES );
168 temp.index = Num_bitmap_files;
172 if ( FindArg("-macdata") )
175 if ( !BigPig ) gr_bitmap_rle_compress( bmp );
176 Num_bitmap_files_new++;
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;
183 GameBitmapOffset[Num_bitmap_files] = 0;
184 GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags;
191 int piggy_register_sound( digi_sound * snd, char * name, int in_file )
195 Assert( Num_sound_files < MAX_SOUND_FILES );
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;
201 SoundOffset[Num_sound_files] = 0;
207 Num_sound_files_new++;
213 bitmap_index piggy_find_bitmap( char * name )
221 if ((t=strchr(name,'#'))!=NULL)
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 );
234 name=alias_list[i].file_name;
241 i = hashtable_search( &AllBitmapsNames, name );
250 int piggy_find_sound( char * name )
254 i = hashtable_search( &AllDigiSndNames, name );
262 CFILE * Piggy_fp = NULL;
264 #define FILENAME_LEN 13
266 char Current_pigfile[FILENAME_LEN] = "";
268 void piggy_close_file()
273 Current_pigfile[0] = 0;
277 int Pigfile_initialized=0;
279 #define PIGFILE_ID MAKE_SIG('G','I','P','P') //PPIG
280 #define PIGFILE_VERSION 2
282 extern char CDROM_dir[];
284 int request_cd(void);
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
294 char sourcePathAndFileCStr[255] = "";
295 char destPathAndFileCStr[255] = "";
297 FILE* sourceFile = NULL;
298 FILE* destFile = NULL;
299 const int BUF_SIZE = 4096;
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] = "";
311 getcwd(oldDirCStr, 255);
313 show_boxed_message("Copying bitmap data from CD...");
314 gr_palette_load(gr_palette); //I don't think this line is really needed
317 //First, delete all PIG files currently in the directory
318 if( !FileFindFirst( "*.pig", &find ) )
323 } while( !FileFindNext( &find ) );
329 //Now, copy over new pig
330 songs_stop_redbook(); //so we can read off the cd
332 // make the source path "<cd volume>:Data:filename.pig"
333 //MWA ConvertCToPStr(filename, pigfileNamePStr);
335 //MWA ConcatPStr(sourcePathAndFilePStr, "\pDescent II:Data:"); // volume ID is cd_VRefNum
336 //MWA ConcatPStr(sourcePathAndFilePStr, pigfileNamePStr);
339 strcpy(sourcePathAndFileCStr, "Descent II:Data:");
340 strcat(sourcePathAndFileCStr, filename);
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);
348 strcpy(destPathAndFileCStr, ":Data:");
349 strcat(destPathAndFileCStr, filename);
351 strcpy(sourcePathAndFilePStr, sourcePathAndFileCStr);
352 strcpy(destPathAndFilePStr, destPathAndFileCStr);
353 c2pstr(sourcePathAndFilePStr);
354 c2pstr(destPathAndFilePStr);
357 // Open the source file
358 sourceFile = fopen(sourcePathAndFileCStr,"rb");
362 if (request_cd() == -1)
363 Error("Cannot load file <%s> from CD",filename);
366 } while (!sourceFile);
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;
376 theErr = PBHGetFInfo(&theSourcePigHFSParams, false);
379 // Error getting file time stamp!! Why? JTS
380 Error("Can't get old file time stamp: <%s>\n", sourcePathAndFileCStr);
383 // Copy the file over
386 // Open the destination file
387 destFile = fopen(destPathAndFileCStr,"wb");
390 Error("Cannot create file: <%s>\n", destPathAndFileCStr);
393 // Copy bytes until the end of the source file
394 while (!feof(sourceFile))
399 bytes_read = fread(buf,1,BUF_SIZE,sourceFile);
400 if (ferror(sourceFile))
401 Error("Cannot read from file <%s>: %s", sourcePathAndFileCStr, strerror(errno));
403 // Assert is bogus Assert(bytes_read == BUF_SIZE || feof(sourceFile));
405 fwrite(buf,1,bytes_read,destFile);
406 if (ferror(destFile))
407 Error("Cannot write to file <%s>: %s",destPathAndFileCStr, strerror(errno));
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));
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))
425 // Error getting file time stamp!! Why? JTS
426 Error("Can't get destination pig file information: <%s>\n", destPathAndFileCStr);
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;
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';
441 // Set the dest file's time stamp to the source file's time stamp values
442 theErr = PBHSetFInfo(&theDestPigHFSParams, false);
444 if ((theErr != noErr) || (theDestPigHFSParams.fileParam.ioResult != noErr))
446 Error("Can't set destination pig file time stamp: <%s>\n", destPathAndFileCStr);
449 theErr = PBHGetFInfo(&theDestPigHFSParams, false);
451 return cfopen(destPathAndFileCStr, "rb");
454 #else //PC Version of copy_pigfile_from_cd is below
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)
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
468 //First, delete all PIG files currently in the directory
470 if( !FileFindFirst( "*.pig", &find ) ) {
473 } while( !FileFindNext( &find ) );
477 //Now, copy over new pig
479 songs_stop_redbook(); //so we can read off the cd
481 //new code to unarj file
482 strcpy(name,CDROM_dir);
483 strcat(name,"descent2.sow");
486 // ret = unarj_specific_file(name,filename,filename);
491 if (ret != EXIT_SUCCESS) {
493 //delete file, so we don't leave partial file
497 if (request_cd() == -1)
499 //NOTE LINK TO ABOVE IF
500 Error("Cannot load file <%s> from CD",filename);
503 } while (ret != EXIT_SUCCESS);
505 return cfopen(filename, "rb");
508 #endif // end of ifdef MAC around copy_pigfile_from_cd
510 //initialize a pigfile, reading headers
511 //returns the size of all the bitmap data
512 void piggy_init_pigfile(char *filename)
516 char temp_name_read[16];
517 grs_bitmap temp_bitmap;
518 DiskBitmapHeader bmh;
519 int header_size, N_bitmaps, data_size, data_start;
521 char name[255]; // filename + path for the mac
524 piggy_close_file(); //close old pig if still open
526 //rename pigfile for shareware
527 if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(filename))
528 filename = DEFAULT_PIGFILE_SHAREWARE;
531 Piggy_fp = cfopen( filename, "rb" );
533 sprintf(name, ":Data:%s", filename);
534 Piggy_fp = cfopen( name, "rb" );
536 #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now.
537 if (Piggy_fp == NULL)
539 Error("Cannot load required file <%s>",name);
541 #endif // end of if def shareware
547 return; //if editor, ok to not have pig, because we'll build one
549 Piggy_fp = copy_pigfile_from_cd(filename);
553 if (Piggy_fp) { //make sure pig is valid type file & is up-to-date
554 int pig_id,pig_version;
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
567 return; //if editor, ok to not have pig, because we'll build one
569 Error("Cannot load required file <%s>",filename);
573 strncpy(Current_pigfile,filename,sizeof(Current_pigfile));
575 N_bitmaps = cfile_read_int(Piggy_fp);
577 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
579 data_start = header_size + cftell(Piggy_fp);
581 data_size = cfilelength(Piggy_fp) - data_start;
583 Num_bitmap_files = 1;
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 );
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;
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;
607 GameBitmapOffset[i+1] = bmh.offset + data_start;
608 Assert( (i+1) == Num_bitmap_files );
609 piggy_register_bitmap( &temp_bitmap, temp_name, 1 );
613 Piggy_bitmap_cache_size = data_size + (data_size/10); //extra mem for new bitmaps
614 Assert( Piggy_bitmap_cache_size > 0 );
616 Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
618 if (piggy_low_memory)
619 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
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;
628 #if defined(MACINTOSH) && defined(SHAREWARE)
629 // load_exit_models();
632 Pigfile_initialized=1;
635 #define FILENAME_LEN 13
636 #define MAX_BITMAPS_PER_BRUSH 30
638 extern int compute_average_pixel(grs_bitmap *new);
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)
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;
657 //rename pigfile for shareware
658 if (stricmp(DEFAULT_PIGFILE, DEFAULT_PIGFILE_SHAREWARE) == 0 && !cfexist(pigname))
659 pigname = DEFAULT_PIGFILE_SHAREWARE;
661 if (strnicmp(Current_pigfile,pigname,sizeof(Current_pigfile))==0)
662 return; //already have correct pig
664 if (!Pigfile_initialized) { //have we ever opened a pigfile?
665 piggy_init_pigfile(pigname); //..no, so do initialization stuff
669 piggy_close_file(); //close old pig if still open
671 Piggy_bitmap_cache_next = 0; //free up cache
673 strncpy(Current_pigfile,pigname,sizeof(Current_pigfile));
676 Piggy_fp = cfopen( pigname, "rb" );
678 sprintf(name, ":Data:%s", pigname);
679 Piggy_fp = cfopen( name, "rb" );
681 #ifdef SHAREWARE // if we are in the shareware version, we must have the pig by now.
682 if (Piggy_fp == NULL)
684 Error("Cannot load required file <%s>",name);
686 #endif // end of if def shareware
691 Piggy_fp = copy_pigfile_from_cd(pigname);
694 if (Piggy_fp) { //make sure pig is valid type file & is up-to-date
695 int pig_id,pig_version;
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
706 if (!Piggy_fp) Error ("Piggy_fp not defined in piggy_new_pigfile.");
711 N_bitmaps = cfile_read_int(Piggy_fp);
713 header_size = N_bitmaps*DISKBITMAPHEADER_SIZE;
715 data_start = header_size + cftell(Piggy_fp);
717 data_size = cfilelength(Piggy_fp) - data_start;
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;
724 if ( bmh.dflags & DBM_FLAG_ABM )
725 sprintf( temp_name, "%s#%d", temp_name_read, bmh.dflags & 63 );
727 strcpy( temp_name, temp_name_read );
729 //Make sure name matches
730 if (strcmp(temp_name,AllBitmaps[i].name)) {
731 //Int3(); //this pig is out of date. Delete it
735 strcpy(AllBitmaps[i].name,temp_name);
737 memset( &temp_bitmap, 0, sizeof(grs_bitmap) );
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;
745 GameBitmapFlags[i] = 0;
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;
753 GameBitmapOffset[i] = bmh.offset + data_start;
755 GameBitmaps[i] = temp_bitmap;
759 N_bitmaps = 0; //no pigfile, so no bitmaps
763 Assert(N_bitmaps == Num_bitmap_files-1);
767 if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
770 //re-read the bitmaps that aren't in this pig
772 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
775 p = strchr(AllBitmaps[i].name,'#');
777 if (p) { //this is an ABM
778 char abmname[FILENAME_LEN];
780 grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
781 int iff_error; //reference parm to avoid warning message
783 char basename[FILENAME_LEN];
786 strcpy(basename,AllBitmaps[i].name);
787 basename[p-AllBitmaps[i].name] = 0; //cut off "#nn" part
789 sprintf( abmname, "%s.abm", basename );
791 iff_error = iff_read_animbrush(abmname,bm,MAX_BITMAPS_PER_BRUSH,&nframes,newpal);
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));
798 for (fnum=0;fnum<nframes; fnum++) {
802 sprintf( tempname, "%s#%d", basename, fnum );
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
808 if ( iff_has_transparency )
809 gr_remap_bitmap_good( bm[fnum], newpal, iff_transparent_color, SuperX );
811 gr_remap_bitmap_good( bm[fnum], newpal, -1, SuperX );
813 bm[fnum]->avg_color = compute_average_pixel(bm[fnum]);
816 if ( FindArg("-macdata") )
817 swap_0_255( bm[fnum] );
819 if ( !BigPig ) gr_bitmap_rle_compress( bm[fnum] );
821 if (bm[fnum]->bm_flags & BM_FLAG_RLE)
822 size = *((int *) bm[fnum]->bm_data);
824 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
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;
831 GameBitmaps[i+fnum] = *bm[fnum];
833 // -- mprintf( (0, "U" ));
837 i += nframes-1; //filled in multiple bitmaps
839 else { //this is a BBM
844 char bbmname[FILENAME_LEN];
847 MALLOC( new, grs_bitmap, 1 );
849 sprintf( bbmname, "%s.bbm", AllBitmaps[i].name );
850 iff_error = iff_read_bitmap(bbmname,new,BM_LINEAR,newpal);
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));
858 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
859 //above makes assumption that supertransparent color is 254
861 if ( iff_has_transparency )
862 gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
864 gr_remap_bitmap_good( new, newpal, -1, SuperX );
866 new->avg_color = compute_average_pixel(new);
869 if ( FindArg("-macdata") )
872 if ( !BigPig ) gr_bitmap_rle_compress( new );
874 if (new->bm_flags & BM_FLAG_RLE)
875 size = *((int *) new->bm_data);
877 size = new->bm_w * new->bm_h;
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;
884 GameBitmaps[i] = *new;
888 // -- mprintf( (0, "U" ));
892 //@@Dont' do these things which are done when writing
893 //@@for (i=0; i < Num_bitmap_files; i++ ) {
894 //@@ bitmap_index bi;
896 //@@ PIGGY_PAGE_IN( bi );
899 //@@piggy_close_file();
901 piggy_write_pigfile(pigname);
903 Current_pigfile[0] = 0; //say no pig, to force reload
905 piggy_new_pigfile(pigname); //read in just-generated pig
909 #endif //ifdef EDITOR
913 ubyte bogus_data[64*64];
914 grs_bitmap bogus_bitmap;
915 ubyte bogus_bitmap_initialized=0;
916 digi_sound bogus_sound;
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
923 #define SNDFILE_ID MAKE_SIG('D','N','S','D') //DSND
924 #define SNDFILE_VERSION 1
928 CFILE * ham_fp = NULL;
930 int sound_offset = 0;
936 ham_fp = cfopen( DEFAULT_HAMFILE, "rb" );
938 sprintf(name, ":Data:%s", DEFAULT_HAMFILE );
939 ham_fp = cfopen( name, "rb" );
942 if (ham_fp == NULL) {
943 Must_write_hamfile = 1;
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);
953 if (ham_id != HAMFILE_ID || Piggy_hamfile_version != HAMFILE_VERSION) {
954 Must_write_hamfile = 1;
955 cfclose(ham_fp); //out of date ham
960 if (Piggy_hamfile_version < 3) // hamfile contains sound info
961 sound_offset = cfile_read_int(ham_fp);
968 cfread( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
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]);
977 if (Piggy_hamfile_version < 3) {
982 DiskSoundHeader sndh;
983 digi_sound temp_sound;
984 char temp_name_read[16];
987 cfseek(ham_fp, sound_offset, SEEK_SET);
988 N_sounds = cfile_read_int(ham_fp);
990 sound_start = cftell(ham_fp);
992 header_size = N_sounds * DISKSOUNDHEADER_SIZE;
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 );
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 ));
1011 SoundBits = d_malloc( sbytes + 16 );
1012 if ( SoundBits == NULL )
1013 Error( "Not enough memory to load sounds\n" );
1015 mprintf(( 0, "\nBitmaps: %d KB Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1017 // piggy_read_sounds(ham_fp);
1029 CFILE * snd_fp = NULL;
1030 int snd_id,snd_version;
1035 DiskSoundHeader sndh;
1036 digi_sound temp_sound;
1037 char temp_name_read[16];
1044 snd_fp = cfopen( DEFAULT_SNDFILE, "rb" );
1046 sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1047 snd_fp = cfopen( name, "rb");
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
1061 N_sounds = cfile_read_int(snd_fp);
1063 sound_start = cftell(snd_fp);
1064 size = cfilelength(snd_fp) - sound_start;
1066 mprintf( (0, "\nReading data (%d KB) ", size/1024 ));
1068 header_size = N_sounds*sizeof(DiskSoundHeader);
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 );
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 ));
1088 SoundBits = d_malloc( sbytes + 16 );
1089 if ( SoundBits == NULL )
1090 Error( "Not enough memory to load sounds\n" );
1092 mprintf(( 0, "\nBitmaps: %d KB Sounds: %d KB\n", Piggy_bitmap_cache_size/1024, sbytes/1024 ));
1094 // piggy_read_sounds(snd_fp);
1101 int piggy_init(void)
1103 int ham_ok=0,snd_ok=0;
1106 hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES );
1107 hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES );
1109 for (i=0; i<MAX_SOUND_FILES; i++ ) {
1110 GameSounds[i].length = 0;
1111 GameSounds[i].data = NULL;
1115 for (i=0; i<MAX_BITMAP_FILES; i++ )
1116 GameBitmapXlat[i] = i;
1118 if ( !bogus_bitmap_initialized ) {
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;
1133 piggy_register_bitmap( &bogus_bitmap, "bogus", 1 );
1134 bogus_sound.length = 64*64;
1135 bogus_sound.data = bogus_data;
1136 GameBitmapOffset[0] = 0;
1139 if ( FindArg( "-bigpig" ))
1142 if ( FindArg( "-lowmem" ))
1143 piggy_low_memory = 1;
1145 if ( FindArg( "-nolowmem" ))
1146 piggy_low_memory = 0;
1148 if (piggy_low_memory)
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));
1158 piggy_init_pigfile(DEFAULT_PIGFILE);
1161 snd_ok = ham_ok = read_hamfile();
1163 if (Piggy_hamfile_version >= 3)
1164 snd_ok = read_sndfile();
1166 atexit(piggy_close);
1168 mprintf ((0,"HamOk=%d SndOk=%d\n",ham_ok,snd_ok));
1169 return (ham_ok && snd_ok); //read ok
1172 int piggy_is_needed(int soundnum)
1176 if ( !digi_lomem ) return 1;
1178 for (i=0; i<MAX_SOUNDS; i++ ) {
1179 if ( (AltSounds[i] < 255) && (Sounds[AltSounds[i]] == soundnum) )
1186 void piggy_read_sounds(void)
1199 fp = cfopen( DEFAULT_SNDFILE, "rb" );
1201 sprintf( name, ":Data:%s", DEFAULT_SNDFILE );
1202 fp = cfopen( name, "rb");
1208 for (i=0; i<Num_sound_files; i++ ) {
1209 digi_sound *snd = &GameSounds[i];
1211 if ( SoundOffset[i] > 0 ) {
1212 if ( piggy_is_needed(i) ) {
1213 cfseek( fp, SoundOffset[i], SEEK_SET );
1215 // Read in the sound data!!!
1218 sbytes += snd->length;
1219 cfread( snd->data, snd->length, 1, fp );
1222 snd->data = (ubyte *) -1;
1228 mprintf(( 0, "\nActual Sound usage: %d KB\n", sbytes/1024 ));
1233 extern int descent_critical_error;
1234 extern unsigned descent_critical_deverror;
1235 extern unsigned descent_critical_errcode;
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" };
1241 void piggy_critical_error()
1243 grs_canvas * save_canv;
1244 grs_font * save_font;
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' );
1252 gr_set_current_canvas(save_canv);
1253 grd_curcanv->cv_font = save_font;
1256 void piggy_bitmap_page_in( bitmap_index bitmap )
1265 Assert( i < MAX_BITMAP_FILES );
1266 Assert( i < Num_bitmap_files );
1267 Assert( Piggy_bitmap_cache_size > 0 );
1269 if ( i < 1 ) return;
1270 if ( i >= MAX_BITMAP_FILES ) return;
1271 if ( i >= Num_bitmap_files ) return;
1273 if ( GameBitmapOffset[i] == 0 ) return; // A read-from-disk bitmap!!!
1275 if ( piggy_low_memory ) {
1277 i = GameBitmapXlat[i]; // Xlat for low-memory settings!
1280 bmp = &GameBitmaps[i];
1282 if ( bmp->bm_flags & BM_FLAG_PAGED_OUT ) {
1286 descent_critical_error = 0;
1287 cfseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
1288 if ( descent_critical_error ) {
1289 piggy_critical_error();
1293 bmp->bm_data = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
1294 bmp->bm_flags = GameBitmapFlags[i];
1296 if ( bmp->bm_flags & BM_FLAG_RLE ) {
1298 descent_critical_error = 0;
1299 zsize = cfile_read_int(Piggy_fp);
1300 if ( descent_critical_error ) {
1301 piggy_critical_error();
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 ) {
1309 piggy_bitmap_page_out_all();
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();
1320 Piggy_bitmap_cache_next += zsize-4;
1322 if (cfilelength(Piggy_fp) == 4929684) // mac version of d2demo.pig
1323 rle_swap_0_255( bmp );
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();
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();
1338 Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1340 if (cfilelength(Piggy_fp) == 4929684) // mac version of d2demo.pig
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" );
1357 if ( piggy_low_memory ) {
1359 GameBitmaps[org_i] = GameBitmaps[i];
1362 //@@Removed from John's code:
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" );
1372 void piggy_bitmap_page_out_all()
1376 Piggy_bitmap_cache_next = 0;
1378 piggy_page_flushed++;
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;
1390 mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1393 void piggy_load_level_data()
1395 piggy_bitmap_page_out_all();
1401 void change_filename_ext( char *dest, char *src, char *ext );
1403 void piggy_write_pigfile(char *filename)
1406 int bitmap_data_start,data_offset;
1407 DiskBitmapHeader bmh;
1409 char subst_name[32];
1412 char tname[FILENAME_LEN];
1414 // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1415 for (i=0; i < Num_bitmap_files; i++ ) {
1418 PIGGY_PAGE_IN( bi );
1420 // -- mprintf( (0, "\n" ));
1424 // -- mprintf( (0, "Creating %s...",filename ));
1426 pig_fp = fopen( filename, "wb" ); //open PIG file
1427 Assert( pig_fp!=NULL );
1429 write_int(PIGFILE_ID,pig_fp);
1430 write_int(PIGFILE_VERSION,pig_fp);
1433 fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1436 bitmap_data_start = ftell(pig_fp);
1437 bitmap_data_start += (Num_bitmap_files-1)*DISKBITMAPHEADER_SIZE;
1438 data_offset = bitmap_data_start;
1440 change_filename_ext(tname,filename,"lst");
1441 fp1 = fopen( tname, "wt" );
1442 change_filename_ext(tname,filename,"all");
1443 fp2 = fopen( tname, "wt" );
1445 for (i=1; i < Num_bitmap_files; i++ ) {
1451 p = strchr(AllBitmaps[i].name,'#');
1458 fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1459 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1461 bmh.dflags = DBM_FLAG_ABM + n;
1465 fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1466 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1470 bmp = &GameBitmaps[i];
1472 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
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 );
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;
1485 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1487 fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1488 data_offset += bmp->bm_rowsize * bmp->bm_h;
1490 fprintf( fp1, ".\n" );
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 ));
1508 bmh.flags &= ~BM_FLAG_PAGED_OUT;
1510 bmh.avg_color=GameBitmaps[i].avg_color;
1511 fwrite( &bmh, DISKBITMAPHEADER_SIZE, 1, pig_fp ); // Mark as a bitmap
1516 mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1517 fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1524 static void write_int(int i,FILE *file)
1526 if (fwrite( &i, sizeof(i), 1, file) != 1)
1527 Error( "Error reading int in gamesave.c" );
1531 void piggy_dump_all()
1535 int org_offset,data_offset=0;
1536 DiskSoundHeader sndh;
1537 int sound_data_start=0;
1540 #ifdef NO_DUMP_SOUNDS
1541 Num_sound_files = 0;
1542 Num_sound_files_new = 0;
1545 if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1548 fp1 = fopen( "ham.lst", "wt" );
1549 fp2 = fopen( "ham.all", "wt" );
1551 if (Must_write_hamfile || Num_bitmap_files_new) {
1553 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1555 ham_fp = fopen( DEFAULT_HAMFILE, "wb" ); //open HAM file
1556 Assert( ham_fp!=NULL );
1558 write_int(HAMFILE_ID,ham_fp);
1559 write_int(HAMFILE_VERSION,ham_fp);
1561 bm_write_all(ham_fp);
1562 xlat_offset = ftell(ham_fp);
1563 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1566 if (Num_bitmap_files_new)
1567 piggy_write_pigfile(DEFAULT_PIGFILE);
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);
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 );
1578 mprintf( (0, "\n" ));
1581 if (Num_sound_files_new) {
1583 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1584 // Now dump sound file
1585 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1586 Assert( ham_fp!=NULL );
1588 write_int(SNDFILE_ID,ham_fp);
1589 write_int(SNDFILE_VERSION,ham_fp);
1591 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1593 mprintf( (0, "\nDumping sounds..." ));
1595 sound_data_start = ftell(ham_fp);
1596 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1597 data_offset = sound_data_start;
1599 for (i=0; i < Num_sound_files; i++ ) {
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;
1607 org_offset = ftell(ham_fp);
1608 fseek( ham_fp, data_offset, SEEK_SET );
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
1616 fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1617 fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1621 mprintf( (0, "\n" ));
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 );
1631 // Never allow the game to run after building ham.
1645 d_free( SoundBits );
1647 hashtable_free( &AllBitmapsNames );
1648 hashtable_free( &AllDigiSndNames );
1652 int piggy_does_bitmap_exist_slow( char * name )
1656 for (i=0; i<Num_bitmap_files; i++ ) {
1657 if ( !strcmp( AllBitmaps[i].name, name) )
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",
1681 int piggy_is_gauge_bitmap( char * base_name )
1684 for (i=0; i<NUM_GAUGE_BITMAPS; i++ ) {
1685 if ( !stricmp( base_name, gauge_bitmap_names[i] ))
1692 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1696 char base_name[ 16 ];
1698 strcpy( subst_name, name );
1699 p = strchr( subst_name, '#' );
1701 frame = atoi( &p[1] );
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 ) ) {
1708 sprintf( subst_name, "%s#%d", base_name, frame-1 );
1714 strcpy( subst_name, name );
1721 // New Windows stuff
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.
1727 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1732 // Essential when switching video modes!
1734 void piggy_bitmap_page_out_all_w()
1740 #ifndef FAST_FILE_IO
1742 * reads a bitmap_index structure from a CFILE
1744 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
1746 bi->index = cfile_read_short(fp);
1750 * reads n bitmap_index structs from a CFILE
1752 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
1756 for (i = 0; i < n; i++)
1757 bi[i].index = cfile_read_short(fp);
1762 * reads a DiskBitmapHeader structure from a CFILE
1764 void DiskBitmapHeader_read(DiskBitmapHeader *dbh, CFILE *fp)
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);
1777 * reads a DiskSoundHeader structure from a CFILE
1779 void DiskSoundHeader_read(DiskSoundHeader *dsh, CFILE *fp)
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);