1 /* $Id: piggy.c,v 1.18 2002-10-10 19:17:37 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.18 2002-10-10 19:17:37 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;
1323 if (cfilelength(Piggy_fp) == 4929684) // mac version of d2demo.pig
1324 rle_swap_0_255( bmp );
1327 // GET JOHN NOW IF YOU GET THIS ASSERT!!!
1328 Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
1329 if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
1330 piggy_bitmap_page_out_all();
1333 descent_critical_error = 0;
1334 temp = cfread( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w, Piggy_fp );
1335 if ( descent_critical_error ) {
1336 piggy_critical_error();
1339 Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
1342 if (cfilelength(Piggy_fp) == 4929684) // mac version of d2demo.pig
1349 //@@if ( bmp->bm_selector ) {
1350 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
1351 //@@ if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1352 //@@ Error( "Error modifying selector base in piggy.c\n" );
1359 if ( piggy_low_memory ) {
1361 GameBitmaps[org_i] = GameBitmaps[i];
1364 //@@Removed from John's code:
1366 //@@ if ( bmp->bm_selector ) {
1367 //@@ if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
1368 //@@ Error( "Error modifying selector base in piggy.c\n" );
1374 void piggy_bitmap_page_out_all()
1378 Piggy_bitmap_cache_next = 0;
1380 piggy_page_flushed++;
1385 for (i=0; i<Num_bitmap_files; i++ ) {
1386 if ( GameBitmapOffset[i] > 0 ) { // Don't page out bitmaps read from disk!!!
1387 GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT;
1388 GameBitmaps[i].bm_data = Piggy_bitmap_cache_data;
1392 mprintf(( 0, "Flushing piggy bitmap cache\n" ));
1395 void piggy_load_level_data()
1397 piggy_bitmap_page_out_all();
1403 void change_filename_ext( char *dest, char *src, char *ext );
1405 void piggy_write_pigfile(char *filename)
1408 int bitmap_data_start,data_offset;
1409 DiskBitmapHeader bmh;
1411 char subst_name[32];
1414 char tname[FILENAME_LEN];
1416 // -- mprintf( (0, "Paging in all piggy bitmaps..." ));
1417 for (i=0; i < Num_bitmap_files; i++ ) {
1420 PIGGY_PAGE_IN( bi );
1422 // -- mprintf( (0, "\n" ));
1426 // -- mprintf( (0, "Creating %s...",filename ));
1428 pig_fp = fopen( filename, "wb" ); //open PIG file
1429 Assert( pig_fp!=NULL );
1431 write_int(PIGFILE_ID,pig_fp);
1432 write_int(PIGFILE_VERSION,pig_fp);
1435 fwrite( &Num_bitmap_files, sizeof(int), 1, pig_fp );
1438 bitmap_data_start = ftell(pig_fp);
1439 bitmap_data_start += (Num_bitmap_files-1)*DISKBITMAPHEADER_SIZE;
1440 data_offset = bitmap_data_start;
1442 change_filename_ext(tname,filename,"lst");
1443 fp1 = fopen( tname, "wt" );
1444 change_filename_ext(tname,filename,"all");
1445 fp2 = fopen( tname, "wt" );
1447 for (i=1; i < Num_bitmap_files; i++ ) {
1453 p = strchr(AllBitmaps[i].name,'#');
1460 fprintf( fp2, "%s.abm\n", AllBitmaps[i].name );
1461 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1463 bmh.dflags = DBM_FLAG_ABM + n;
1467 fprintf( fp2, "%s.bbm\n", AllBitmaps[i].name );
1468 memcpy( bmh.name, AllBitmaps[i].name, 8 );
1472 bmp = &GameBitmaps[i];
1474 Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) );
1477 fprintf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h );
1478 org_offset = ftell(pig_fp);
1479 bmh.offset = data_offset - bitmap_data_start;
1480 fseek( pig_fp, data_offset, SEEK_SET );
1482 if ( bmp->bm_flags & BM_FLAG_RLE ) {
1483 size = (int *)bmp->bm_data;
1484 fwrite( bmp->bm_data, sizeof(ubyte), *size, pig_fp );
1485 data_offset += *size;
1487 fprintf( fp1, ", and is already compressed to %d bytes.\n", *size );
1489 fwrite( bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h, pig_fp );
1490 data_offset += bmp->bm_rowsize * bmp->bm_h;
1492 fprintf( fp1, ".\n" );
1494 fseek( pig_fp, org_offset, SEEK_SET );
1495 Assert( GameBitmaps[i].bm_w < 4096 );
1496 bmh.width = (GameBitmaps[i].bm_w & 0xff);
1497 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
1498 Assert( GameBitmaps[i].bm_h < 4096 );
1499 bmh.height = GameBitmaps[i].bm_h;
1500 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
1501 bmh.flags = GameBitmaps[i].bm_flags;
1502 if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name )) {
1503 bitmap_index other_bitmap;
1504 other_bitmap = piggy_find_bitmap( subst_name );
1505 GameBitmapXlat[i] = other_bitmap.index;
1506 bmh.flags |= BM_FLAG_PAGED_OUT;
1507 //mprintf(( 0, "Skipping bitmap %d\n", i ));
1508 //mprintf(( 0, "Marking '%s' as substitutible\n", AllBitmaps[i].name ));
1510 bmh.flags &= ~BM_FLAG_PAGED_OUT;
1512 bmh.avg_color=GameBitmaps[i].avg_color;
1513 fwrite( &bmh, DISKBITMAPHEADER_SIZE, 1, pig_fp ); // Mark as a bitmap
1518 mprintf( (0, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ));
1519 fprintf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
1526 static void write_int(int i,FILE *file)
1528 if (fwrite( &i, sizeof(i), 1, file) != 1)
1529 Error( "Error reading int in gamesave.c" );
1533 void piggy_dump_all()
1537 int org_offset,data_offset=0;
1538 DiskSoundHeader sndh;
1539 int sound_data_start=0;
1542 #ifdef NO_DUMP_SOUNDS
1543 Num_sound_files = 0;
1544 Num_sound_files_new = 0;
1547 if (!Must_write_hamfile && (Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) )
1550 fp1 = fopen( "ham.lst", "wt" );
1551 fp2 = fopen( "ham.all", "wt" );
1553 if (Must_write_hamfile || Num_bitmap_files_new) {
1555 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1557 ham_fp = fopen( DEFAULT_HAMFILE, "wb" ); //open HAM file
1558 Assert( ham_fp!=NULL );
1560 write_int(HAMFILE_ID,ham_fp);
1561 write_int(HAMFILE_VERSION,ham_fp);
1563 bm_write_all(ham_fp);
1564 xlat_offset = ftell(ham_fp);
1565 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1568 if (Num_bitmap_files_new)
1569 piggy_write_pigfile(DEFAULT_PIGFILE);
1571 //free up memeory used by new bitmaps
1572 for (i=Num_bitmap_files-Num_bitmap_files_new;i<Num_bitmap_files;i++)
1573 d_free(GameBitmaps[i].bm_data);
1575 //next thing must be done after pig written
1576 fseek( ham_fp, xlat_offset, SEEK_SET );
1577 fwrite( GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1, ham_fp );
1580 mprintf( (0, "\n" ));
1583 if (Num_sound_files_new) {
1585 mprintf( (0, "Creating %s...",DEFAULT_HAMFILE));
1586 // Now dump sound file
1587 ham_fp = fopen( DEFAULT_SNDFILE, "wb" );
1588 Assert( ham_fp!=NULL );
1590 write_int(SNDFILE_ID,ham_fp);
1591 write_int(SNDFILE_VERSION,ham_fp);
1593 fwrite( &Num_sound_files, sizeof(int), 1, ham_fp );
1595 mprintf( (0, "\nDumping sounds..." ));
1597 sound_data_start = ftell(ham_fp);
1598 sound_data_start += Num_sound_files*sizeof(DiskSoundHeader);
1599 data_offset = sound_data_start;
1601 for (i=0; i < Num_sound_files; i++ ) {
1604 snd = &GameSounds[i];
1605 strcpy( sndh.name, AllSounds[i].name );
1606 sndh.length = GameSounds[i].length;
1607 sndh.offset = data_offset - sound_data_start;
1609 org_offset = ftell(ham_fp);
1610 fseek( ham_fp, data_offset, SEEK_SET );
1612 sndh.data_length = GameSounds[i].length;
1613 fwrite( snd->data, sizeof(ubyte), snd->length, ham_fp );
1614 data_offset += snd->length;
1615 fseek( ham_fp, org_offset, SEEK_SET );
1616 fwrite( &sndh, sizeof(DiskSoundHeader), 1, ham_fp ); // Mark as a bitmap
1618 fprintf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, snd->length );
1619 fprintf( fp2, "%s.raw\n", AllSounds[i].name );
1623 mprintf( (0, "\n" ));
1626 fprintf( fp1, "Total sound size: %d bytes\n", data_offset-sound_data_start);
1627 mprintf( (0, " Dumped %d assorted sounds.\n", Num_sound_files ));
1628 fprintf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files );
1633 // Never allow the game to run after building ham.
1647 d_free( SoundBits );
1649 hashtable_free( &AllBitmapsNames );
1650 hashtable_free( &AllDigiSndNames );
1654 int piggy_does_bitmap_exist_slow( char * name )
1658 for (i=0; i<Num_bitmap_files; i++ ) {
1659 if ( !strcmp( AllBitmaps[i].name, name) )
1666 #define NUM_GAUGE_BITMAPS 23
1667 char * gauge_bitmap_names[NUM_GAUGE_BITMAPS] = {
1668 "gauge01", "gauge01b",
1669 "gauge02", "gauge02b",
1670 "gauge06", "gauge06b",
1671 "targ01", "targ01b",
1672 "targ02", "targ02b",
1673 "targ03", "targ03b",
1674 "targ04", "targ04b",
1675 "targ05", "targ05b",
1676 "targ06", "targ06b",
1677 "gauge18", "gauge18b",
1683 int piggy_is_gauge_bitmap( char * base_name )
1686 for (i=0; i<NUM_GAUGE_BITMAPS; i++ ) {
1687 if ( !stricmp( base_name, gauge_bitmap_names[i] ))
1694 int piggy_is_substitutable_bitmap( char * name, char * subst_name )
1698 char base_name[ 16 ];
1700 strcpy( subst_name, name );
1701 p = strchr( subst_name, '#' );
1703 frame = atoi( &p[1] );
1705 strcpy( base_name, subst_name );
1706 if ( !piggy_is_gauge_bitmap( base_name )) {
1707 sprintf( subst_name, "%s#%d", base_name, frame+1 );
1708 if ( piggy_does_bitmap_exist_slow( subst_name ) ) {
1710 sprintf( subst_name, "%s#%d", base_name, frame-1 );
1716 strcpy( subst_name, name );
1723 // New Windows stuff
1725 // windows bitmap page in
1726 // Page in a bitmap, if ddraw, then page it into a ddsurface in
1727 // 'video' memory. if that fails, page it in normally.
1729 void piggy_bitmap_page_in_w( bitmap_index bitmap, int ddraw )
1734 // Essential when switching video modes!
1736 void piggy_bitmap_page_out_all_w()
1742 #ifndef FAST_FILE_IO
1744 * reads a bitmap_index structure from a CFILE
1746 void bitmap_index_read(bitmap_index *bi, CFILE *fp)
1748 bi->index = cfile_read_short(fp);
1752 * reads n bitmap_index structs from a CFILE
1754 int bitmap_index_read_n(bitmap_index *bi, int n, CFILE *fp)
1758 for (i = 0; i < n; i++)
1759 bi[i].index = cfile_read_short(fp);
1764 * reads a DiskBitmapHeader structure from a CFILE
1766 void DiskBitmapHeader_read(DiskBitmapHeader *dbh, CFILE *fp)
1768 cfread(dbh->name, 8, 1, fp);
1769 dbh->dflags = cfile_read_byte(fp);
1770 dbh->width = cfile_read_byte(fp);
1771 dbh->height = cfile_read_byte(fp);
1772 dbh->wh_extra = cfile_read_byte(fp);
1773 dbh->flags = cfile_read_byte(fp);
1774 dbh->avg_color = cfile_read_byte(fp);
1775 dbh->offset = cfile_read_int(fp);
1779 * reads a DiskSoundHeader structure from a CFILE
1781 void DiskSoundHeader_read(DiskSoundHeader *dsh, CFILE *fp)
1783 cfread(dsh->name, 8, 1, fp);
1784 dsh->length = cfile_read_int(fp);
1785 dsh->data_length = cfile_read_int(fp);
1786 dsh->offset = cfile_read_int(fp);