Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Functions for managing the pig files.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. #include "pstypes.h"
  30. #include "strutil.h"
  31. #include "inferno.h"
  32. #include "gr.h"
  33. #include "grdef.h"
  34. #include "u_mem.h"
  35. #include "iff.h"
  36. #include "dxxerror.h"
  37. #include "sounds.h"
  38. #include "songs.h"
  39. #include "bm.h"
  40. #include "hash.h"
  41. #include "common/2d/bitmap.h"
  42. #include "args.h"
  43. #include "palette.h"
  44. #include "gamefont.h"
  45. #include "gamepal.h"
  46. #include "physfsx.h"
  47. #include "rle.h"
  48. #include "screens.h"
  49. #include "piggy.h"
  50. #include "gamemine.h"
  51. #include "textures.h"
  52. #include "texmerge.h"
  53. #include "paging.h"
  54. #include "game.h"
  55. #include "text.h"
  56. #include "vclip.h"
  57. #include "newmenu.h"
  58. #include "makesig.h"
  59. #include "console.h"
  60. #include "compiler-cf_assert.h"
  61. #include "compiler-range_for.h"
  62. #include "d_range.h"
  63. #include "partial_range.h"
  64. #include <memory>
  65.  
  66. #if defined(DXX_BUILD_DESCENT_I)
  67. #include "custom.h"
  68. #include "snddecom.h"
  69. #define DEFAULT_PIGFILE_REGISTERED      "descent.pig"
  70.  
  71. #elif defined(DXX_BUILD_DESCENT_II)
  72. #define DEFAULT_PIGFILE_REGISTERED      "groupa.pig"
  73. #define DEFAULT_PIGFILE_SHAREWARE       "d2demo.pig"
  74. #define DEFAULT_HAMFILE_REGISTERED      "descent2.ham"
  75. #define DEFAULT_HAMFILE_SHAREWARE       "d2demo.ham"
  76.  
  77. #define D1_PALETTE "palette.256"
  78.  
  79. #define DEFAULT_SNDFILE ((Piggy_hamfile_version < 3)?DEFAULT_HAMFILE_SHAREWARE:(GameArg.SndDigiSampleRate==SAMPLE_RATE_22K)?"descent2.s22":"descent2.s11")
  80.  
  81. #define MAC_ALIEN1_PIGSIZE      5013035
  82. #define MAC_ALIEN2_PIGSIZE      4909916
  83. #define MAC_FIRE_PIGSIZE        4969035
  84. #define MAC_GROUPA_PIGSIZE      4929684 // also used for mac shareware
  85. #define MAC_ICE_PIGSIZE         4923425
  86. #define MAC_WATER_PIGSIZE       4832403
  87.  
  88. unsigned Num_aliases;
  89. std::array<alias, MAX_ALIASES> alias_list;
  90.  
  91. int Piggy_hamfile_version = 0;
  92. #endif
  93.  
  94. static std::unique_ptr<ubyte[]> BitmapBits;
  95. static std::unique_ptr<ubyte[]> SoundBits;
  96.  
  97. struct SoundFile
  98. {
  99.         char    name[15];
  100. };
  101.  
  102. #if defined(DXX_BUILD_DESCENT_II)
  103. namespace {
  104. #endif
  105. hashtable AllBitmapsNames;
  106. hashtable AllDigiSndNames;
  107. std::array<int, MAX_BITMAP_FILES> GameBitmapOffset;
  108. #if defined(DXX_BUILD_DESCENT_II)
  109. }
  110. #endif
  111.  
  112. unsigned Num_bitmap_files;
  113. int Num_sound_files = 0;
  114.  
  115. namespace dsx {
  116. std::array<digi_sound, MAX_SOUND_FILES> GameSounds;
  117. static std::array<int, MAX_SOUND_FILES> SoundOffset;
  118. GameBitmaps_array GameBitmaps;
  119. }
  120.  
  121. #if defined(DXX_BUILD_DESCENT_I)
  122. #define DBM_FLAG_LARGE  128             // Flags added onto the flags struct in b
  123. static
  124. #endif
  125. std::array<BitmapFile, MAX_BITMAP_FILES> AllBitmaps;
  126. static std::array<SoundFile, MAX_SOUND_FILES> AllSounds;
  127.  
  128. #define DBM_FLAG_ABM    64 // animated bitmap
  129.  
  130. static int Piggy_bitmap_cache_size;
  131. static int Piggy_bitmap_cache_next;
  132. static uint8_t *Piggy_bitmap_cache_data;
  133. static std::array<uint8_t, MAX_BITMAP_FILES> GameBitmapFlags;
  134. static std::array<uint16_t, MAX_BITMAP_FILES> GameBitmapXlat;
  135.  
  136. #if defined(DXX_BUILD_DESCENT_I)
  137. #define PIGGY_BUFFER_SIZE (2048*1024)
  138. #elif defined(DXX_BUILD_DESCENT_II)
  139. #define PIGFILE_ID              MAKE_SIG('G','I','P','P') //PPIG
  140. #define PIGFILE_VERSION         2
  141. #define PIGGY_BUFFER_SIZE (2400*1024)
  142. #endif
  143. #define PIGGY_SMALL_BUFFER_SIZE (1400*1024)             // size of buffer when CGameArg.SysLowMem is set
  144.  
  145. static RAIIPHYSFS_File Piggy_fp;
  146.  
  147. ubyte bogus_bitmap_initialized=0;
  148. std::array<uint8_t, 64 * 64> bogus_data;
  149. namespace dsx {
  150. digi_sound bogus_sound;
  151. }
  152.  
  153. #if defined(DXX_BUILD_DESCENT_I)
  154. grs_bitmap bogus_bitmap;
  155. int MacPig = 0; // using the Macintosh pigfile?
  156. int PCSharePig = 0; // using PC Shareware pigfile?
  157. static std::array<int, MAX_SOUND_FILES> SoundCompressed;
  158. #elif defined(DXX_BUILD_DESCENT_II)
  159. char Current_pigfile[FILENAME_LEN] = "";
  160. int Pigfile_initialized=0;
  161.  
  162. static std::unique_ptr<ubyte[]> Bitmap_replacement_data;
  163.  
  164. #define BM_FLAGS_TO_COPY (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT \
  165.                          | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE | BM_FLAG_RLE_BIG)
  166. #endif
  167.  
  168. #define DBM_NUM_FRAMES  63
  169.  
  170. struct DiskBitmapHeader
  171. {
  172.         char name[8];
  173.         ubyte dflags;           // bits 0-5 anim frame num, bit 6 abm flag
  174.         ubyte width;            // low 8 bits here, 4 more bits in wh_extra
  175.         ubyte height;           // low 8 bits here, 4 more bits in wh_extra
  176. #if defined(DXX_BUILD_DESCENT_II)
  177.         ubyte wh_extra;         // bits 0-3 width, bits 4-7 height
  178. #endif
  179.         ubyte flags;
  180.         ubyte avg_color;
  181.         int offset;
  182. } __pack__;
  183. #if defined(DXX_BUILD_DESCENT_I)
  184. static_assert(sizeof(DiskBitmapHeader) == 0x11, "sizeof(DiskBitmapHeader) must be 0x11");
  185. #elif defined(DXX_BUILD_DESCENT_II)
  186. static_assert(sizeof(DiskBitmapHeader) == 0x12, "sizeof(DiskBitmapHeader) must be 0x12");
  187.  
  188. #define DISKBITMAPHEADER_D1_SIZE 17 // no wh_extra
  189. #endif
  190.  
  191. struct DiskSoundHeader
  192. {
  193.         char name[8];
  194.         int length;
  195.         int data_length;
  196.         int offset;
  197. } __pack__;
  198.  
  199. #if defined(DXX_BUILD_DESCENT_II)
  200. static void free_bitmap_replacements();
  201. static void free_d1_tmap_nums();
  202. #if DXX_USE_EDITOR
  203. static int piggy_is_substitutable_bitmap(char * name, char (&subst_name)[32]);
  204. static void piggy_write_pigfile(const char *filename);
  205. static void write_int(int i,PHYSFS_File *file);
  206. #endif
  207. static int piggy_is_needed(int soundnum);
  208. #endif
  209.  
  210. namespace dcx {
  211.  
  212. static void get_bitmap_name_from_header(std::array<char, 13> &output_name, const DiskBitmapHeader &bmh)
  213. {
  214.         if (bmh.dflags & DBM_FLAG_ABM)
  215.                 snprintf(output_name.data(), output_name.size(), "%.8s#%d", bmh.name, bmh.dflags & DBM_NUM_FRAMES);
  216.         else
  217.         {
  218.                 memcpy(output_name.data(), bmh.name, 8);
  219.                 output_name[8] = 0;
  220.         }
  221. }
  222.  
  223. }
  224.  
  225. /*
  226.  * reads a DiskBitmapHeader structure from a PHYSFS_File
  227.  */
  228. namespace dsx {
  229. static void DiskBitmapHeader_read(DiskBitmapHeader *dbh, PHYSFS_File *fp)
  230. {
  231.         PHYSFS_read(fp, dbh->name, 8, 1);
  232.         dbh->dflags = PHYSFSX_readByte(fp);
  233.         dbh->width = PHYSFSX_readByte(fp);
  234.         dbh->height = PHYSFSX_readByte(fp);
  235. #if defined(DXX_BUILD_DESCENT_II)
  236.         dbh->wh_extra = PHYSFSX_readByte(fp);
  237. #endif
  238.         dbh->flags = PHYSFSX_readByte(fp);
  239.         dbh->avg_color = PHYSFSX_readByte(fp);
  240.         dbh->offset = PHYSFSX_readInt(fp);
  241. }
  242. }
  243.  
  244. /*
  245.  * reads a DiskSoundHeader structure from a PHYSFS_File
  246.  */
  247. static void DiskSoundHeader_read(DiskSoundHeader *dsh, PHYSFS_File *fp)
  248. {
  249.         PHYSFS_read(fp, dsh->name, 8, 1);
  250.         dsh->length = PHYSFSX_readInt(fp);
  251.         dsh->data_length = PHYSFSX_readInt(fp);
  252.         dsh->offset = PHYSFSX_readInt(fp);
  253. }
  254.  
  255. #if defined(DXX_BUILD_DESCENT_II)
  256. /*
  257.  * reads a descent 1 DiskBitmapHeader structure from a PHYSFS_File
  258.  */
  259. static void DiskBitmapHeader_d1_read(DiskBitmapHeader *dbh, PHYSFS_File *fp)
  260. {
  261.         PHYSFS_read(fp, dbh->name, 8, 1);
  262.         dbh->dflags = PHYSFSX_readByte(fp);
  263.         dbh->width = PHYSFSX_readByte(fp);
  264.         dbh->height = PHYSFSX_readByte(fp);
  265.         dbh->wh_extra = 0;
  266.         dbh->flags = PHYSFSX_readByte(fp);
  267.         dbh->avg_color = PHYSFSX_readByte(fp);
  268.         dbh->offset = PHYSFSX_readInt(fp);
  269. }
  270. #endif
  271.  
  272. void swap_0_255(grs_bitmap &bmp)
  273. {
  274.         auto a = [](uint8_t &c) {
  275.                 if (c == 0)
  276.                         c = 255;
  277.                 else if (c == 255)
  278.                         c = 0;
  279.         };
  280.         auto d = bmp.get_bitmap_data();
  281.         std::for_each(d, d + (bmp.bm_h * bmp.bm_w), a);
  282. }
  283.  
  284. namespace dsx {
  285.  
  286. bitmap_index piggy_register_bitmap(grs_bitmap &bmp, const char *const name, const int in_file)
  287. {
  288.         bitmap_index temp;
  289.         assert(Num_bitmap_files < AllBitmaps.size());
  290.  
  291.         temp.index = Num_bitmap_files;
  292.  
  293.         if (!in_file) {
  294. #if defined(DXX_BUILD_DESCENT_II)
  295. #if DXX_USE_EDITOR
  296.                 if ( GameArg.EdiMacData )
  297.                         swap_0_255(bmp);
  298. #endif
  299. #endif
  300.                 if (CGameArg.DbgNoCompressPigBitmap)
  301.                         gr_bitmap_rle_compress(bmp);
  302.         }
  303. #if defined(DXX_BUILD_DESCENT_II)
  304.         else if (SoundOffset[Num_sound_files] == 0)
  305.                 SoundOffset[Num_sound_files] = -1;              // make sure this sound's data is not individually freed
  306. #endif
  307.  
  308.         auto &abn = AllBitmaps[Num_bitmap_files].name;
  309.         abn.back() = 0;
  310.         strncpy(abn.data(), name, abn.size() - 1);
  311.         hashtable_insert(&AllBitmapsNames, AllBitmaps[Num_bitmap_files].name.data(), Num_bitmap_files);
  312. #if defined(DXX_BUILD_DESCENT_I)
  313.         GameBitmaps[Num_bitmap_files] = bmp;
  314. #endif
  315.         if ( !in_file ) {
  316.                 GameBitmapOffset[Num_bitmap_files] = 0;
  317.                 GameBitmapFlags[Num_bitmap_files] = bmp.get_flags();
  318.         }
  319.         Num_bitmap_files++;
  320.  
  321.         return temp;
  322. }
  323.  
  324. int piggy_register_sound( digi_sound * snd, const char * name, int in_file )
  325. {
  326.         int i;
  327.  
  328.         Assert( Num_sound_files < MAX_SOUND_FILES );
  329.  
  330.         strncpy( AllSounds[Num_sound_files].name, name, 12 );
  331.         hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files );
  332.         GameSounds[Num_sound_files] = *snd;
  333. #if defined(DXX_BUILD_DESCENT_I)
  334. //added/moved on 11/13/99 by Victor Rachels to ready for changing freq
  335. //#ifdef ALLEGRO
  336.         GameSounds[Num_sound_files].bits = snd->bits;
  337.         GameSounds[Num_sound_files].freq = snd->freq;
  338.  
  339. #ifdef ALLEGRO
  340. //end this section move - VR
  341.         GameSounds[Num_sound_files].priority = 128;
  342.         GameSounds[Num_sound_files].loop_start = 0;
  343.         GameSounds[Num_sound_files].loop_end = GameSounds[Num_sound_files].len;
  344.         GameSounds[Num_sound_files].param = -1;
  345. #endif
  346. #endif
  347.         if ( !in_file ) {
  348.                 SoundOffset[Num_sound_files] = 0;      
  349.         }
  350. #if defined(DXX_BUILD_DESCENT_I)
  351.         else if (SoundOffset[Num_sound_files] == 0)
  352.                 SoundOffset[Num_sound_files] = -1;              // make sure this sound's data is not individually freed
  353. #endif
  354.  
  355.         i = Num_sound_files;
  356.         Num_sound_files++;
  357.         return i;
  358. }
  359.  
  360. bitmap_index piggy_find_bitmap(const char * name)
  361. {
  362.         bitmap_index bmp;
  363.  
  364.         bmp.index = 0;
  365.  
  366. #if defined(DXX_BUILD_DESCENT_II)
  367.         size_t namelen;
  368.         const char *t;
  369.         if ((t=strchr(name,'#'))!=NULL)
  370.                 namelen = t - name;
  371.         else
  372.                 namelen = strlen(name);
  373.  
  374.         char temp[FILENAME_LEN];
  375.         range_for (auto &i, partial_const_range(alias_list, Num_aliases))
  376.                 if (i.alias_name[namelen] == 0 && d_strnicmp(name, i.alias_name,namelen)==0) {
  377.                         if (t) {                //extra stuff for ABMs
  378.                                 struct splitpath_t path;
  379.                                 d_splitpath(i.file_name, &path);
  380.                                 snprintf(temp, sizeof(temp), "%.*s%s\n", DXX_ptrdiff_cast_int(path.base_end - path.base_start), path.base_start, t);
  381.                                 name = temp;
  382.                         }
  383.                         else
  384.                                 name = i.file_name;
  385.                         break;
  386.                 }
  387. #endif
  388.  
  389.         int i;
  390.         i = hashtable_search( &AllBitmapsNames, name );
  391.         Assert( i != 0 );
  392.         if ( i < 0 )
  393.                 return bmp;
  394.  
  395.         bmp.index = i;
  396.         return bmp;
  397. }
  398.  
  399. }
  400.  
  401. int piggy_find_sound(const char *name)
  402. {
  403.         int i;
  404.  
  405.         i = hashtable_search( &AllDigiSndNames, name );
  406.  
  407.         if ( i < 0 )
  408.                 return 255;
  409.  
  410.         return i;
  411. }
  412.  
  413. namespace dsx {
  414. static void piggy_close_file()
  415. {
  416.         if (Piggy_fp)
  417.         {
  418.                 Piggy_fp.reset();
  419. #if defined(DXX_BUILD_DESCENT_II)
  420.                 Current_pigfile[0] = 0;
  421. #endif
  422.         }
  423. }
  424. }
  425.  
  426. #if defined(DXX_BUILD_DESCENT_I)
  427. int properties_init()
  428. {
  429.         int sbytes = 0;
  430.         std::array<char, 13> temp_name;
  431.         digi_sound temp_sound;
  432.         DiskBitmapHeader bmh;
  433.         DiskSoundHeader sndh;
  434.         int header_size, N_bitmaps, N_sounds;
  435.         int size;
  436.         int Pigdata_start;
  437.         int pigsize;
  438.         int retval;
  439.         GameSounds = {};
  440.         SoundOffset = {};
  441.  
  442.         static_assert(GameBitmapXlat.size() == GameBitmaps.size(), "size mismatch");
  443.         for (unsigned i = 0; i < GameBitmaps.size(); ++i)
  444.         {
  445.                 GameBitmapXlat[i] = i;
  446.                 GameBitmaps[i].set_flags(BM_FLAG_PAGED_OUT);
  447.         }
  448.  
  449.         if ( !bogus_bitmap_initialized )        {
  450.                 ubyte c;
  451.                 bogus_bitmap_initialized = 1;
  452.                 c = gr_find_closest_color( 0, 0, 63 );
  453.                 bogus_data.fill(c);
  454.                 c = gr_find_closest_color( 63, 0, 0 );
  455.                 // Make a big red X !
  456.                 range_for (const unsigned i, xrange(64u))
  457.                 {
  458.                         bogus_data[i*64+i] = c;
  459.                         bogus_data[i*64+(63-i)] = c;
  460.                 }
  461.                 gr_init_bitmap(bogus_bitmap, bm_mode::linear, 0, 0, 64, 64, 64, bogus_data.data());
  462.                 piggy_register_bitmap(bogus_bitmap, "bogus", 1);
  463. #ifdef ALLEGRO
  464.                 bogus_sound.len = 64*64;
  465. #else
  466.         bogus_sound.length = 64*64;
  467. #endif
  468.                 bogus_sound.data = bogus_data.data();
  469. //added on 11/13/99 by Victor Rachels to ready for changing freq
  470.                 bogus_sound.freq = 11025;
  471.                 bogus_sound.bits = 8;
  472. //end this section addition - VR
  473.                 GameBitmapOffset[0] = 0;
  474.         }
  475.        
  476.         Piggy_fp = PHYSFSX_openReadBuffered(DEFAULT_PIGFILE_REGISTERED);
  477.         if (!Piggy_fp)
  478.         {
  479.                 if (!PHYSFSX_exists("BITMAPS.TBL",1) && !PHYSFSX_exists("BITMAPS.BIN",1))
  480.                         Error("Cannot find " DEFAULT_PIGFILE_REGISTERED " or BITMAPS.TBL");
  481.                 return 1;       // need to run gamedata_read_tbl
  482.         }
  483.  
  484.         pigsize = PHYSFS_fileLength(Piggy_fp);
  485.         switch (pigsize) {
  486.                 case D1_SHARE_BIG_PIGSIZE:
  487.                 case D1_SHARE_10_PIGSIZE:
  488.                 case D1_SHARE_PIGSIZE:
  489.                         PCSharePig = 1;
  490.                         Pigdata_start = 0;
  491.                         break;
  492.                 case D1_10_BIG_PIGSIZE:
  493.                 case D1_10_PIGSIZE:
  494.                         Pigdata_start = 0;
  495.                         break;
  496.                 default:
  497.                         Warning("Unknown size for " DEFAULT_PIGFILE_REGISTERED);
  498.                         Int3();
  499.                         DXX_BOOST_FALLTHROUGH;
  500.                 case D1_MAC_PIGSIZE:
  501.                 case D1_MAC_SHARE_PIGSIZE:
  502.                         MacPig = 1;
  503.                         DXX_BOOST_FALLTHROUGH;
  504.                 case D1_PIGSIZE:
  505.                 case D1_OEM_PIGSIZE:
  506.                         Pigdata_start = PHYSFSX_readInt(Piggy_fp );
  507.                         break;
  508.         }
  509.        
  510.         HiresGFXAvailable = MacPig;     // for now at least
  511.  
  512.         if (PCSharePig)
  513.                 retval = PIGGY_PC_SHAREWARE;    // run gamedata_read_tbl in shareware mode
  514.         else if (GameArg.EdiNoBm || (!PHYSFSX_exists("BITMAPS.TBL",1) && !PHYSFSX_exists("BITMAPS.BIN",1)))
  515.         {
  516.                 properties_read_cmp(Vclip, Piggy_fp);   // Note connection to above if!!!
  517.                 range_for (auto &i, GameBitmapXlat)
  518.                 {
  519.                         i = PHYSFSX_readShort(Piggy_fp);
  520.                         if (PHYSFS_eof(Piggy_fp))
  521.                                 break;
  522.                 }
  523.                 retval = 0;     // don't run gamedata_read_tbl
  524.         }
  525.         else
  526.                 retval = 1;     // run gamedata_read_tbl
  527.  
  528.         PHYSFSX_fseek( Piggy_fp, Pigdata_start, SEEK_SET );
  529.         size = PHYSFS_fileLength(Piggy_fp) - Pigdata_start;
  530.  
  531.         N_bitmaps = PHYSFSX_readInt(Piggy_fp);
  532.         size -= sizeof(int);
  533.         N_sounds = PHYSFSX_readInt(Piggy_fp);
  534.         size -= sizeof(int);
  535.  
  536.         header_size = (N_bitmaps*sizeof(DiskBitmapHeader)) + (N_sounds*sizeof(DiskSoundHeader));
  537.  
  538.         for (unsigned i = 0; i < N_bitmaps; ++i)
  539.         {
  540.                 DiskBitmapHeader_read(&bmh, Piggy_fp);
  541.                
  542.                 GameBitmapFlags[i+1] = 0;
  543.                 if ( bmh.flags & BM_FLAG_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_TRANSPARENT;
  544.                 if ( bmh.flags & BM_FLAG_SUPER_TRANSPARENT ) GameBitmapFlags[i+1] |= BM_FLAG_SUPER_TRANSPARENT;
  545.                 if ( bmh.flags & BM_FLAG_NO_LIGHTING ) GameBitmapFlags[i+1] |= BM_FLAG_NO_LIGHTING;
  546.                 if ( bmh.flags & BM_FLAG_RLE ) GameBitmapFlags[i+1] |= BM_FLAG_RLE;
  547.  
  548.                 GameBitmapOffset[i+1] = bmh.offset + header_size + (sizeof(int)*2) + Pigdata_start;
  549.                 Assert( (i+1) == Num_bitmap_files );
  550.  
  551.                 //size -= sizeof(DiskBitmapHeader);
  552.                 get_bitmap_name_from_header(temp_name, bmh);
  553.  
  554.                 grs_bitmap temp_bitmap{};
  555.                 const auto iwidth = (bmh.dflags & DBM_FLAG_LARGE) ? bmh.width + 256 : bmh.width;
  556.                 gr_init_bitmap(temp_bitmap, bm_mode::linear, 0, 0,
  557.                         iwidth, bmh.height,
  558.                         iwidth, Piggy_bitmap_cache_data);
  559.                 temp_bitmap.add_flags(BM_FLAG_PAGED_OUT);
  560. #if !DXX_USE_OGL
  561.                 temp_bitmap.avg_color = bmh.avg_color;
  562. #endif
  563.  
  564.                 if (MacPig)
  565.                 {
  566.                         // HACK HACK HACK!!!!!
  567.                         if (!d_strnicmp(bmh.name, "cockpit") || !d_strnicmp(bmh.name, "status") || !d_strnicmp(bmh.name, "rearview")) {
  568.                                 temp_bitmap.bm_w = temp_bitmap.bm_rowsize = 640;
  569.                                 if (GameBitmapFlags[i+1] & BM_FLAG_RLE)
  570.                                         GameBitmapFlags[i+1] |= BM_FLAG_RLE_BIG;
  571.                         }
  572.                         if (!d_strnicmp(bmh.name, "cockpit") || !d_strnicmp(bmh.name, "rearview"))
  573.                                 temp_bitmap.bm_h = 480;
  574.                 }
  575.                
  576.                 piggy_register_bitmap(temp_bitmap, temp_name.data(), 1);
  577.         }
  578.  
  579.         if (!MacPig)
  580.         {
  581.         for (unsigned i = 0; i < N_sounds; ++i)
  582.         {
  583.                 DiskSoundHeader_read(&sndh, Piggy_fp);
  584.                
  585.                 //size -= sizeof(DiskSoundHeader);
  586. #ifdef ALLEGRO
  587.                 temp_sound.len = sndh.length;
  588. #else
  589.                 temp_sound.length = sndh.length;
  590. #endif
  591.  
  592. //added on 11/13/99 by Victor Rachels to ready for changing freq
  593.                 temp_sound.bits = 8;
  594.                 temp_sound.freq = 11025;
  595. //end this section addition - VR
  596.                 temp_sound.data = reinterpret_cast<uint8_t *>(sndh.offset + header_size + (sizeof(int)*2)+Pigdata_start);
  597.                 SoundOffset[Num_sound_files] = sndh.offset + header_size + (sizeof(int)*2)+Pigdata_start;
  598.                 if (PCSharePig)
  599.                         SoundCompressed[Num_sound_files] = sndh.data_length;
  600.                 std::array<char, 9> temp_name_read;
  601.                 memcpy(temp_name_read.data(), sndh.name, temp_name_read.size() - 1);
  602.                 temp_name_read.back() = 0;
  603.                 piggy_register_sound(&temp_sound, temp_name_read.data(), 1);
  604.                 sbytes += sndh.length;
  605.         }
  606.  
  607.                 SoundBits = std::make_unique<ubyte[]>(sbytes + 16);
  608.         }
  609.  
  610. #if 1   //def EDITOR
  611.         Piggy_bitmap_cache_size = size - header_size - sbytes + 16;
  612.         Assert( Piggy_bitmap_cache_size > 0 );
  613. #else
  614.         Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
  615.         if (CGameArg.SysLowMem)
  616.                 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
  617. #endif
  618.         BitmapBits = std::make_unique<ubyte[]>(Piggy_bitmap_cache_size);
  619.         Piggy_bitmap_cache_data = BitmapBits.get();
  620.         Piggy_bitmap_cache_next = 0;
  621.  
  622.         return retval;
  623. }
  624. #elif defined(DXX_BUILD_DESCENT_II)
  625.  
  626. //initialize a pigfile, reading headers
  627. //returns the size of all the bitmap data
  628. void piggy_init_pigfile(const char *filename)
  629. {
  630.         int i;
  631.         std::array<char, 13> temp_name;
  632.         DiskBitmapHeader bmh;
  633.         int header_size, N_bitmaps, data_start;
  634. #if DXX_USE_EDITOR
  635.         int data_size;
  636. #endif
  637.  
  638.         piggy_close_file();             //close old pig if still open
  639.  
  640.         Piggy_fp = PHYSFSX_openReadBuffered(filename);
  641.        
  642.         //try pigfile for shareware
  643.         if (!Piggy_fp)
  644.                 Piggy_fp = PHYSFSX_openReadBuffered(DEFAULT_PIGFILE_SHAREWARE);
  645.  
  646.         if (Piggy_fp) {                         //make sure pig is valid type file & is up-to-date
  647.                 int pig_id,pig_version;
  648.  
  649.                 pig_id = PHYSFSX_readInt(Piggy_fp);
  650.                 pig_version = PHYSFSX_readInt(Piggy_fp);
  651.                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
  652.                         Piggy_fp.reset(); //out of date pig
  653.                                                 //..so pretend it's not here
  654.                 }
  655.         }
  656.  
  657.         if (!Piggy_fp) {
  658.  
  659. #if DXX_USE_EDITOR
  660.                         return;         //if editor, ok to not have pig, because we'll build one
  661.                 #else
  662.                         Error("Cannot load required file <%s>",filename);
  663.                 #endif
  664.         }
  665.  
  666.         strncpy(Current_pigfile, filename, sizeof(Current_pigfile) - 1);
  667.  
  668.         N_bitmaps = PHYSFSX_readInt(Piggy_fp);
  669.  
  670.         header_size = N_bitmaps * sizeof(DiskBitmapHeader);
  671.  
  672.         data_start = header_size + PHYSFS_tell(Piggy_fp);
  673. #if DXX_USE_EDITOR
  674.         data_size = PHYSFS_fileLength(Piggy_fp) - data_start;
  675. #endif
  676.         Num_bitmap_files = 1;
  677.  
  678.         for (i=0; i<N_bitmaps; i++ )
  679.         {
  680.                 int width;
  681.                 grs_bitmap *bm = &GameBitmaps[i + 1];
  682.                
  683.                 DiskBitmapHeader_read(&bmh, Piggy_fp);
  684.                 get_bitmap_name_from_header(temp_name, bmh);
  685.                 width = bmh.width + (static_cast<short>(bmh.wh_extra & 0x0f) << 8);
  686.                 gr_init_bitmap(*bm, bm_mode::linear, 0, 0, width, bmh.height + (static_cast<short>(bmh.wh_extra & 0xf0) << 4), width, NULL);
  687.                 bm->set_flags(BM_FLAG_PAGED_OUT);
  688. #if !DXX_USE_OGL
  689.                 bm->avg_color = bmh.avg_color;
  690. #endif
  691.  
  692.                 GameBitmapFlags[i+1] = bmh.flags & BM_FLAGS_TO_COPY;
  693.  
  694.                 GameBitmapOffset[i+1] = bmh.offset + data_start;
  695.                 Assert( (i+1) == Num_bitmap_files );
  696.                 piggy_register_bitmap(*bm, temp_name.data(), 1);
  697.         }
  698.  
  699. #if DXX_USE_EDITOR
  700.         Piggy_bitmap_cache_size = data_size + (data_size/10);   //extra mem for new bitmaps
  701.         Assert( Piggy_bitmap_cache_size > 0 );
  702. #else
  703.         Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE;
  704.         if (CGameArg.SysLowMem)
  705.                 Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE;
  706. #endif
  707.         BitmapBits = std::make_unique<ubyte[]>(Piggy_bitmap_cache_size);
  708.         Piggy_bitmap_cache_data = BitmapBits.get();
  709.         Piggy_bitmap_cache_next = 0;
  710.  
  711.         Pigfile_initialized=1;
  712. }
  713.  
  714. //reads in a new pigfile (for new palette)
  715. //returns the size of all the bitmap data
  716. void piggy_new_pigfile(char *pigname)
  717. {
  718.         int i;
  719.         std::array<char, 13> temp_name;
  720.         DiskBitmapHeader bmh;
  721.         int header_size, N_bitmaps, data_start;
  722. #if DXX_USE_EDITOR
  723.         int must_rewrite_pig = 0;
  724. #endif
  725.  
  726.         d_strlwr(pigname);
  727.  
  728.         if (d_strnicmp(Current_pigfile, pigname, sizeof(Current_pigfile)) == 0 // correct pig already loaded
  729.             && !Bitmap_replacement_data) // no need to reload: no bitmaps were altered
  730.                 return;
  731.  
  732.         if (!Pigfile_initialized) {                     //have we ever opened a pigfile?
  733.                 piggy_init_pigfile(pigname);            //..no, so do initialization stuff
  734.                 return;
  735.         }
  736.         else
  737.                 piggy_close_file();             //close old pig if still open
  738.  
  739.         Piggy_bitmap_cache_next = 0;            //free up cache
  740.  
  741.         strncpy(Current_pigfile, pigname, sizeof(Current_pigfile) - 1);
  742.  
  743.         Piggy_fp = PHYSFSX_openReadBuffered(pigname);
  744.  
  745.         //try pigfile for shareware
  746.         if (!Piggy_fp)
  747.                 Piggy_fp = PHYSFSX_openReadBuffered(DEFAULT_PIGFILE_SHAREWARE);
  748.        
  749.         if (Piggy_fp) {  //make sure pig is valid type file & is up-to-date
  750.                 int pig_id,pig_version;
  751.  
  752.                 pig_id = PHYSFSX_readInt(Piggy_fp);
  753.                 pig_version = PHYSFSX_readInt(Piggy_fp);
  754.                 if (pig_id != PIGFILE_ID || pig_version != PIGFILE_VERSION) {
  755.                         Piggy_fp.reset();              //out of date pig
  756.                                                 //..so pretend it's not here
  757.                 }
  758.         }
  759.  
  760. #if !DXX_USE_EDITOR
  761.         if (!Piggy_fp)
  762.                 Error("Cannot open correct version of <%s>", pigname);
  763. #endif
  764.  
  765.         if (Piggy_fp) {
  766.  
  767.                 N_bitmaps = PHYSFSX_readInt(Piggy_fp);
  768.  
  769.                 header_size = N_bitmaps * sizeof(DiskBitmapHeader);
  770.  
  771.                 data_start = header_size + PHYSFS_tell(Piggy_fp);
  772.  
  773.                 for (i=1; i<=N_bitmaps; i++ )
  774.                 {
  775.                         grs_bitmap *bm = &GameBitmaps[i];
  776.                         int width;
  777.                        
  778.                         DiskBitmapHeader_read(&bmh, Piggy_fp);
  779.                         get_bitmap_name_from_header(temp_name, bmh);
  780. #if DXX_USE_EDITOR
  781.                         //Make sure name matches
  782.                         if (strcmp(temp_name.data(), AllBitmaps[i].name.data()))
  783.                         {
  784.                                 //Int3();       //this pig is out of date.  Delete it
  785.                                 must_rewrite_pig=1;
  786.                         }
  787. #endif
  788.        
  789.                         AllBitmaps[i].name = temp_name;
  790.  
  791.                         width = bmh.width + (static_cast<short>(bmh.wh_extra & 0x0f) << 8);
  792.                         gr_set_bitmap_data(*bm, NULL);  // free ogl texture
  793.                         gr_init_bitmap(*bm, bm_mode::linear, 0, 0, width, bmh.height + (static_cast<short>(bmh.wh_extra & 0xf0) << 4), width, NULL);
  794.                         bm->set_flags(BM_FLAG_PAGED_OUT);
  795. #if !DXX_USE_OGL
  796.                         bm->avg_color = bmh.avg_color;
  797. #endif
  798.  
  799.                         GameBitmapFlags[i] = bmh.flags & BM_FLAGS_TO_COPY;
  800.        
  801.                         GameBitmapOffset[i] = bmh.offset + data_start;
  802.                 }
  803.         }
  804.         else
  805.                 N_bitmaps = 0;          //no pigfile, so no bitmaps
  806.  
  807. #if !DXX_USE_EDITOR
  808.  
  809.         Assert(N_bitmaps == Num_bitmap_files-1);
  810.  
  811.         #else
  812.  
  813.         if (must_rewrite_pig || (N_bitmaps < Num_bitmap_files-1)) {
  814.                 int size;
  815.  
  816.                 //re-read the bitmaps that aren't in this pig
  817.  
  818.                 for (i=N_bitmaps+1;i<Num_bitmap_files;i++) {
  819.                         if (const auto p = strchr(AllBitmaps[i].name.data(), '#'))
  820.                         {   // this is an ABM == animated bitmap
  821.                                 char abmname[FILENAME_LEN];
  822.                                 unsigned fnum;
  823.                                 int iff_error;          //reference parm to avoid warning message
  824.                                 palette_array_t newpal;
  825.                                 char basename[FILENAME_LEN];
  826.                                 unsigned nframes;
  827.  
  828.                                 const std::size_t len = p - AllBitmaps[i].name.data();
  829.                                 cf_assert(len < AllBitmaps[i].name.size());
  830.                                 memcpy(basename, AllBitmaps[i].name.data(), len);
  831.                                 basename[len] = 0;
  832.  
  833.                                 snprintf(abmname, sizeof(abmname), "%.8s.abm", basename);
  834.  
  835.                                 std::array<std::unique_ptr<grs_main_bitmap>, MAX_BITMAPS_PER_BRUSH> bm;
  836.                                 iff_error = iff_read_animbrush(abmname,bm,&nframes,newpal);
  837.  
  838.                                 if (iff_error != IFF_NO_ERROR)  {
  839.                                         Error("File %s - IFF error: %s",abmname,iff_errormsg(iff_error));
  840.                                 }
  841.                        
  842.                                 for (fnum=0;fnum<nframes; fnum++)       {
  843.                                         char tempname[20];
  844.                                         int SuperX;
  845.  
  846.                                         snprintf(tempname, sizeof(tempname), "%s#%u", basename, fnum);
  847.  
  848.                                         //SuperX = (GameBitmaps[i+fnum].bm_flags&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
  849.                                         SuperX = (GameBitmapFlags[i+fnum]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
  850.                                         //above makes assumption that supertransparent color is 254
  851.  
  852.                                         gr_remap_bitmap_good(*bm[fnum].get(), newpal, iff_has_transparency ? iff_transparent_color : -1, SuperX);
  853.  
  854. #if !DXX_USE_OGL
  855.                                         bm[fnum]->avg_color = compute_average_pixel(bm[fnum].get());
  856. #endif
  857.  
  858.                                         if ( GameArg.EdiMacData )
  859.                                                 swap_0_255(*bm[fnum].get());
  860.  
  861.                                         if (CGameArg.DbgNoCompressPigBitmap)
  862.                                                 gr_bitmap_rle_compress(*bm[fnum].get());
  863.  
  864.                                         if (bm[fnum]->get_flag_mask(BM_FLAG_RLE))
  865.                                                 size = *reinterpret_cast<const int *>(bm[fnum]->bm_data);
  866.                                         else
  867.                                                 size = bm[fnum]->bm_w * bm[fnum]->bm_h;
  868.  
  869.                                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],bm[fnum]->bm_data,size);
  870.                                         d_free(bm[fnum]->bm_mdata);
  871.                                         bm[fnum]->bm_mdata = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
  872.                                         Piggy_bitmap_cache_next += size;
  873.  
  874.                                         GameBitmaps[i+fnum] = std::move(*bm[fnum]);
  875.                                 }
  876.  
  877.                                 i += nframes-1;         //filled in multiple bitmaps
  878.                         }
  879.                         else {          //this is a BBM
  880.  
  881.                                 grs_bitmap n;
  882.                                 palette_array_t newpal;
  883.                                 int iff_error;
  884.                                 char bbmname[FILENAME_LEN];
  885.                                 int SuperX;
  886.  
  887.                                 snprintf(bbmname, sizeof(bbmname), "%.8s.bbm", AllBitmaps[i].name.data());
  888.                                 iff_error = iff_read_bitmap(bbmname, n, &newpal);
  889.  
  890.                                 if (iff_error != IFF_NO_ERROR)          {
  891.                                         Error("File %s - IFF error: %s",bbmname,iff_errormsg(iff_error));
  892.                                 }
  893.  
  894.                                 SuperX = (GameBitmapFlags[i]&BM_FLAG_SUPER_TRANSPARENT)?254:-1;
  895.                                 //above makes assumption that supertransparent color is 254
  896.  
  897.                                 gr_remap_bitmap_good(n, newpal, iff_has_transparency ? iff_transparent_color : -1, SuperX);
  898.  
  899. #if !DXX_USE_OGL
  900.                                 n.avg_color = compute_average_pixel(&n);
  901. #endif
  902.  
  903.                                 if ( GameArg.EdiMacData )
  904.                                         swap_0_255(n);
  905.  
  906.                                 if (CGameArg.DbgNoCompressPigBitmap)
  907.                                         gr_bitmap_rle_compress(n);
  908.  
  909.                                 if (n.get_flag_mask(BM_FLAG_RLE))
  910.                                         size = *reinterpret_cast<const int *>(n.bm_data);
  911.                                 else
  912.                                         size = n.bm_w * n.bm_h;
  913.  
  914.                                 memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next],n.bm_data,size);
  915.                                 d_free(n.bm_mdata);
  916.                                 n.bm_mdata = &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next];
  917.                                 Piggy_bitmap_cache_next += size;
  918.  
  919.                                 GameBitmaps[i] = n;
  920.                         }
  921.                 }
  922.  
  923.                 //@@Dont' do these things which are done when writing
  924.                 //@@for (i=0; i < Num_bitmap_files; i++ )       {
  925.                 //@@    bitmap_index bi;
  926.                 //@@    bi.index = i;
  927.                 //@@    PIGGY_PAGE_IN( bi );
  928.                 //@@}
  929.                 //@@
  930.                 //@@piggy_close_file();
  931.  
  932.                 piggy_write_pigfile(pigname);
  933.  
  934.                 Current_pigfile[0] = 0;                 //say no pig, to force reload
  935.  
  936.                 piggy_new_pigfile(pigname);             //read in just-generated pig
  937.  
  938.  
  939.         }
  940.         #endif  //ifdef EDITOR
  941.  
  942. }
  943.  
  944. #define HAMFILE_ID              MAKE_SIG('!','M','A','H') //HAM!
  945. #define HAMFILE_VERSION 3
  946. //version 1 -> 2:  save marker_model_num
  947. //version 2 -> 3:  removed sound files
  948.  
  949. #define SNDFILE_ID              MAKE_SIG('D','N','S','D') //DSND
  950. #define SNDFILE_VERSION 1
  951.  
  952. int read_hamfile()
  953. {
  954.         int ham_id;
  955.         int sound_offset = 0;
  956.         int shareware = 0;
  957.  
  958.         auto ham_fp = PHYSFSX_openReadBuffered(DEFAULT_HAMFILE_REGISTERED);
  959.        
  960.         if (!ham_fp)
  961.         {
  962.                 ham_fp = PHYSFSX_openReadBuffered(DEFAULT_HAMFILE_SHAREWARE);
  963.                 if (ham_fp)
  964.                 {
  965.                         shareware = 1;
  966.                         GameArg.SndDigiSampleRate = SAMPLE_RATE_11K;
  967.                         if (CGameArg.SndDisableSdlMixer)
  968.                         {
  969.                                 digi_close();
  970.                                 digi_init();
  971.                         }
  972.                 }
  973.         }
  974.  
  975.         if (!ham_fp) {
  976.                 return 0;
  977.         }
  978.  
  979.         //make sure ham is valid type file & is up-to-date
  980.         ham_id = PHYSFSX_readInt(ham_fp);
  981.         Piggy_hamfile_version = PHYSFSX_readInt(ham_fp);
  982.         if (ham_id != HAMFILE_ID)
  983.                 Error("Cannot open ham file %s or %s\n", DEFAULT_HAMFILE_REGISTERED, DEFAULT_HAMFILE_SHAREWARE);
  984. #if 0
  985.         if (ham_id != HAMFILE_ID || Piggy_hamfile_version != HAMFILE_VERSION) {
  986.                 Must_write_hamfile = 1;
  987.                 PHYSFS_close(ham_fp);                                           //out of date ham
  988.                 return 0;
  989.         }
  990. #endif
  991.  
  992.         if (Piggy_hamfile_version < 3) // hamfile contains sound info, probably PC demo
  993.         {
  994.                 sound_offset = PHYSFSX_readInt(ham_fp);
  995.                
  996.                 if (shareware) // deal with interactive PC demo
  997.                 {
  998.                         GameArg.GfxSkipHiresGFX = 1;
  999.                         //CGameArg.SysLowMem = 1;
  1000.                 }
  1001.         }
  1002.  
  1003.         #if 1 //ndef EDITOR
  1004.         {
  1005.                 bm_read_all(Vclip, ham_fp);
  1006.                 //PHYSFS_read( ham_fp, GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1 );
  1007.                 range_for (auto &i, GameBitmapXlat)
  1008.                 {
  1009.                         i = PHYSFSX_readShort(ham_fp);
  1010.                         if (PHYSFS_eof(ham_fp))
  1011.                                 break;
  1012.                 }
  1013.         }
  1014.         #endif
  1015.  
  1016.         if (Piggy_hamfile_version < 3) {
  1017.                 int N_sounds;
  1018.                 int sound_start;
  1019.                 int header_size;
  1020.                 int i;
  1021.                 DiskSoundHeader sndh;
  1022.                 digi_sound temp_sound;
  1023.                 char temp_name_read[16];
  1024.                 int sbytes = 0;
  1025.                 static int justonce = 1;
  1026.  
  1027.                 if (!justonce)
  1028.                 {
  1029.                         return 1;
  1030.                 }
  1031.                 justonce = 0;
  1032.  
  1033.                 PHYSFSX_fseek(ham_fp, sound_offset, SEEK_SET);
  1034.                 N_sounds = PHYSFSX_readInt(ham_fp);
  1035.  
  1036.                 sound_start = PHYSFS_tell(ham_fp);
  1037.  
  1038.                 header_size = N_sounds * sizeof(DiskSoundHeader);
  1039.  
  1040.                 //Read sounds
  1041.  
  1042.                 for (i=0; i<N_sounds; i++ ) {
  1043.                         DiskSoundHeader_read(&sndh, ham_fp);
  1044.                         temp_sound.length = sndh.length;
  1045.                         temp_sound.data = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(sndh.offset + header_size + sound_start));
  1046.                         SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
  1047.                         memcpy( temp_name_read, sndh.name, 8 );
  1048.                         temp_name_read[8] = 0;
  1049.                         piggy_register_sound( &temp_sound, temp_name_read, 1 );
  1050.                         if (piggy_is_needed(i))
  1051.                                 sbytes += sndh.length;
  1052.                 }
  1053.                 SoundBits = std::make_unique<ubyte[]>(sbytes + 16);
  1054.         }
  1055.         return 1;
  1056. }
  1057.  
  1058. #if defined(DXX_BUILD_DESCENT_I)
  1059. static
  1060. #endif
  1061. int read_sndfile()
  1062. {
  1063.         int snd_id,snd_version;
  1064.         int N_sounds;
  1065.         int sound_start;
  1066.         int header_size;
  1067.         int i;
  1068.         DiskSoundHeader sndh;
  1069.         digi_sound temp_sound;
  1070.         char temp_name_read[16];
  1071.         int sbytes = 0;
  1072.  
  1073.         auto snd_fp = PHYSFSX_openReadBuffered(DEFAULT_SNDFILE);
  1074.         if (!snd_fp)
  1075.                 return 0;
  1076.  
  1077.         //make sure soundfile is valid type file & is up-to-date
  1078.         snd_id = PHYSFSX_readInt(snd_fp);
  1079.         snd_version = PHYSFSX_readInt(snd_fp);
  1080.         if (snd_id != SNDFILE_ID || snd_version != SNDFILE_VERSION) {
  1081.                 return 0;
  1082.         }
  1083.  
  1084.         N_sounds = PHYSFSX_readInt(snd_fp);
  1085.  
  1086.         sound_start = PHYSFS_tell(snd_fp);
  1087.         header_size = N_sounds*sizeof(DiskSoundHeader);
  1088.  
  1089.         //Read sounds
  1090.  
  1091.         for (i=0; i<N_sounds; i++ ) {
  1092.                 DiskSoundHeader_read(&sndh, snd_fp);
  1093.                 temp_sound.length = sndh.length;
  1094.                 temp_sound.data = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(sndh.offset + header_size + sound_start));
  1095.                 SoundOffset[Num_sound_files] = sndh.offset + header_size + sound_start;
  1096.                 memcpy( temp_name_read, sndh.name, 8 );
  1097.                 temp_name_read[8] = 0;
  1098.                 piggy_register_sound( &temp_sound, temp_name_read, 1 );
  1099.                 if (piggy_is_needed(i))
  1100.                         sbytes += sndh.length;
  1101.         }
  1102.         SoundBits = std::make_unique<ubyte[]>(sbytes + 16);
  1103.         return 1;
  1104. }
  1105.  
  1106. int properties_init(void)
  1107. {
  1108.         int ham_ok=0,snd_ok=0;
  1109.         for (unsigned i = 0; i < MAX_SOUND_FILES; ++i)
  1110.         {
  1111.                 GameSounds[i].length = 0;
  1112.                 GameSounds[i].data = NULL;
  1113.                 SoundOffset[i] = 0;
  1114.         }
  1115.  
  1116.         for (unsigned i = 0; i < GameBitmapXlat.size(); ++i)
  1117.         {
  1118.                 GameBitmapXlat[i] = i;
  1119.         }
  1120.  
  1121.         if ( !bogus_bitmap_initialized )        {
  1122.                 ubyte c;
  1123.  
  1124.                 bogus_bitmap_initialized = 1;
  1125.                 c = gr_find_closest_color( 0, 0, 63 );
  1126.                 bogus_data.fill(c);
  1127.                 c = gr_find_closest_color( 63, 0, 0 );
  1128.                 // Make a big red X !
  1129.                 range_for (const unsigned i, xrange(64u))
  1130.                 {
  1131.                         bogus_data[i*64+i] = c;
  1132.                         bogus_data[i*64+(63-i)] = c;
  1133.                 }
  1134.                 gr_init_bitmap(GameBitmaps[Num_bitmap_files], bm_mode::linear, 0, 0, 64, 64, 64, bogus_data.data());
  1135.                 piggy_register_bitmap(GameBitmaps[Num_bitmap_files], "bogus", 1);
  1136.                 bogus_sound.length = 64*64;
  1137.                 bogus_sound.data = bogus_data.data();
  1138.                 GameBitmapOffset[0] = 0;
  1139.         }
  1140.  
  1141.         snd_ok = ham_ok = read_hamfile();
  1142.  
  1143.         if (Piggy_hamfile_version >= 3)
  1144.         {
  1145.                 snd_ok = read_sndfile();
  1146.                 if (!snd_ok)
  1147.                         Error("Cannot open sound file: %s\n", DEFAULT_SNDFILE);
  1148.         }
  1149.  
  1150.         return (ham_ok && snd_ok);               //read ok
  1151. }
  1152. #endif
  1153.  
  1154. static int piggy_is_needed(int soundnum)
  1155. {
  1156.         if (!CGameArg.SysLowMem)
  1157.                 return 1;
  1158.  
  1159.         range_for (auto i, AltSounds)
  1160.         {
  1161.                 if (i < 255 && Sounds[i] == soundnum)
  1162.                         return 1;
  1163.         }
  1164.         return 0;
  1165. }
  1166.  
  1167. #if defined(DXX_BUILD_DESCENT_I)
  1168. void piggy_read_sounds(int pc_shareware)
  1169. {
  1170.         uint8_t * ptr;
  1171.         int i, sbytes;
  1172.         int lastsize = 0;
  1173.  
  1174.         if (MacPig)
  1175.         {
  1176.                 // Read Mac sounds converted to RAW format (too messy to read them directly from the resource fork code-wise)
  1177.                 char soundfile[32] = "Sounds/sounds.array";
  1178.                 // hack for Mac Demo
  1179.                 if (auto array = PHYSFSX_openReadBuffered(soundfile))
  1180.                 {
  1181.                         if (PHYSFS_read(array, Sounds, Sounds.size(), 1) != 1)  // make the 'Sounds' index array match with the sounds we're about to read in
  1182.                         {
  1183.                                 con_printf(CON_URGENT,"Warning: Can't read Sounds/sounds.array: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); // Pierre-Marie Baty -- work around PHYSFS_getLastError() deprecation
  1184.                                 return;
  1185.                         }
  1186.                 }
  1187.                 else if (PHYSFSX_fsize(DEFAULT_PIGFILE_REGISTERED) == D1_MAC_SHARE_PIGSIZE)
  1188.                 {
  1189.                         con_printf(CON_URGENT,"Warning: Missing Sounds/sounds.array for Mac data files");
  1190.                         return;
  1191.                 }
  1192.  
  1193.                 for (i = 0; i < MAX_SOUND_FILES; i++)
  1194.                 {
  1195.                         snprintf(soundfile, sizeof(soundfile), "SND%04d.raw", i);
  1196.                         if (ds_load(0, soundfile) == 255)
  1197.                                 break;
  1198.                 }
  1199.  
  1200.                 return;
  1201.         }
  1202.  
  1203.         ptr = SoundBits.get();
  1204.         sbytes = 0;
  1205.  
  1206.         RAIIdmem<uint8_t[]> lastbuf;
  1207.         for (i=0; i<Num_sound_files; i++ )
  1208.         {
  1209.                 digi_sound *snd = &GameSounds[i];
  1210.  
  1211.                 if ( SoundOffset[i] > 0 )
  1212.                 {
  1213.                         if ( piggy_is_needed(i) )
  1214.                         {
  1215.                                 PHYSFSX_fseek( Piggy_fp, SoundOffset[i], SEEK_SET );
  1216.  
  1217.                                 // Read in the sound data!!!
  1218.                                 snd->data = ptr;
  1219. #ifdef ALLEGRO
  1220.                                 ptr += snd->len;
  1221.                                 sbytes += snd->len;
  1222. #else
  1223.                                 ptr += snd->length;
  1224.                                 sbytes += snd->length;
  1225. #endif
  1226.                 //Arne's decompress for shareware on all soundcards - Tim@Rikers.org
  1227.                                 if (pc_shareware)
  1228.                                 {
  1229.                                         if (lastsize < SoundCompressed[i]) {
  1230.                                                 MALLOC(lastbuf, uint8_t[], SoundCompressed[i]);
  1231.                                         }
  1232.                                         PHYSFS_read( Piggy_fp, lastbuf, SoundCompressed[i], 1 );
  1233.                                         sound_decompress(lastbuf.get(), SoundCompressed[i], snd->data);
  1234.                                 }
  1235.                                 else
  1236. #ifdef ALLEGRO
  1237.                                         PHYSFS_read( Piggy_fp, snd->data, snd->len, 1 );
  1238. #else
  1239.                                         PHYSFS_read( Piggy_fp, snd->data, snd->length, 1 );
  1240. #endif
  1241.                         }
  1242.                 }
  1243.         }
  1244. }
  1245. #elif defined(DXX_BUILD_DESCENT_II)
  1246. void piggy_read_sounds(void)
  1247. {
  1248.         uint8_t * ptr;
  1249.         int i, sbytes;
  1250.  
  1251.         ptr = SoundBits.get();
  1252.         sbytes = 0;
  1253.         auto fp = PHYSFSX_openReadBuffered(DEFAULT_SNDFILE);
  1254.         if (!fp)
  1255.                 return;
  1256.  
  1257.         for (i=0; i<Num_sound_files; i++ )      {
  1258.                 digi_sound *snd = &GameSounds[i];
  1259.  
  1260.                 if ( SoundOffset[i] > 0 )       {
  1261.                         if ( piggy_is_needed(i) )       {
  1262.                                 PHYSFSX_fseek( fp, SoundOffset[i], SEEK_SET );
  1263.  
  1264.                                 // Read in the sound data!!!
  1265.                                 snd->data = ptr;
  1266.                                 ptr += snd->length;
  1267.                                 sbytes += snd->length;
  1268.                                 PHYSFS_read( fp, snd->data, snd->length, 1 );
  1269.                         }
  1270.                         else
  1271.                                 snd->data = reinterpret_cast<uint8_t *>(-1);
  1272.                 }
  1273.         }
  1274. }
  1275. #endif
  1276.  
  1277. namespace dsx {
  1278. void piggy_bitmap_page_in( bitmap_index bitmap )
  1279. {
  1280.         grs_bitmap * bmp;
  1281.         int i,org_i;
  1282.  
  1283.         org_i = 0;
  1284.  
  1285.         i = bitmap.index;
  1286.         Assert( i >= 0 );
  1287.         Assert( i < MAX_BITMAP_FILES );
  1288.         Assert( i < Num_bitmap_files );
  1289.         Assert( Piggy_bitmap_cache_size > 0 );
  1290.  
  1291.         if ( i < 1 ) return;
  1292.         if ( i >= MAX_BITMAP_FILES ) return;
  1293.         if ( i >= Num_bitmap_files ) return;
  1294.  
  1295.         if ( GameBitmapOffset[i] == 0 ) return;         // A read-from-disk bitmap!!!
  1296.  
  1297.         if (CGameArg.SysLowMem)
  1298.         {
  1299.                 org_i = i;
  1300.                 i = GameBitmapXlat[i];          // Xlat for low-memory settings!
  1301.         }
  1302.  
  1303.         bmp = &GameBitmaps[i];
  1304.  
  1305.         if (bmp->get_flag_mask(BM_FLAG_PAGED_OUT))
  1306.         {
  1307.                 pause_game_world_time p;
  1308.  
  1309.         ReDoIt:
  1310.                 PHYSFSX_fseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET );
  1311.  
  1312.                 gr_set_bitmap_flags(*bmp, GameBitmapFlags[i]);
  1313. #if defined(DXX_BUILD_DESCENT_I)
  1314.                 gr_set_bitmap_data (*bmp, &Piggy_bitmap_cache_data [Piggy_bitmap_cache_next]);
  1315. #endif
  1316.  
  1317.                 if (bmp->get_flag_mask(BM_FLAG_RLE))
  1318.                 {
  1319.                         int zsize = PHYSFSX_readInt(Piggy_fp);
  1320. #if defined(DXX_BUILD_DESCENT_I)
  1321.  
  1322.                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
  1323.                         Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
  1324.                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
  1325.                                 piggy_bitmap_page_out_all();
  1326.                                 goto ReDoIt;
  1327.                         }
  1328.                         memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], &zsize, sizeof(int) );
  1329.                         Piggy_bitmap_cache_next += sizeof(int);
  1330.                         PHYSFS_read( Piggy_fp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, zsize-4 );
  1331.                         if (MacPig)
  1332.                         {
  1333.                                 rle_swap_0_255(*bmp);
  1334.                                 memcpy(&zsize, bmp->bm_data, 4);
  1335.                         }
  1336.                         Piggy_bitmap_cache_next += zsize-4;
  1337. #elif defined(DXX_BUILD_DESCENT_II)
  1338.                         int pigsize = PHYSFS_fileLength(Piggy_fp);
  1339.  
  1340.                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
  1341.                         //Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size );
  1342.                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
  1343.                                 Int3();
  1344.                                 piggy_bitmap_page_out_all();
  1345.                                 goto ReDoIt;
  1346.                         }
  1347.                         PHYSFS_read( Piggy_fp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next+4], 1, zsize-4 );
  1348.                         PUT_INTEL_INT(&Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], zsize);
  1349.                         gr_set_bitmap_data(*bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
  1350.  
  1351. #ifndef MACDATA
  1352.                         switch (pigsize) {
  1353.                         default:
  1354.                                 if (!GameArg.EdiMacData)
  1355.                                         break;
  1356.                                 DXX_BOOST_FALLTHROUGH;
  1357.                         case MAC_ALIEN1_PIGSIZE:
  1358.                         case MAC_ALIEN2_PIGSIZE:
  1359.                         case MAC_FIRE_PIGSIZE:
  1360.                         case MAC_GROUPA_PIGSIZE:
  1361.                         case MAC_ICE_PIGSIZE:
  1362.                         case MAC_WATER_PIGSIZE:
  1363.                                 rle_swap_0_255(*bmp);
  1364.                                 memcpy(&zsize, bmp->bm_data, 4);
  1365.                                 break;
  1366.                         }
  1367. #endif
  1368.  
  1369.                         Piggy_bitmap_cache_next += zsize;
  1370.                         if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) {
  1371.                                 Int3();
  1372.                                 piggy_bitmap_page_out_all();
  1373.                                 goto ReDoIt;
  1374.                         }
  1375. #endif
  1376.  
  1377.                 } else {
  1378.                         // GET JOHN NOW IF YOU GET THIS ASSERT!!!
  1379.                         Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size );
  1380.                         if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) {
  1381.                                 piggy_bitmap_page_out_all();
  1382.                                 goto ReDoIt;
  1383.                         }
  1384.                         PHYSFS_read( Piggy_fp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w );
  1385. #if defined(DXX_BUILD_DESCENT_I)
  1386.                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
  1387.                         if (MacPig)
  1388.                                 swap_0_255(*bmp);
  1389. #elif defined(DXX_BUILD_DESCENT_II)
  1390.                         int pigsize = PHYSFS_fileLength(Piggy_fp);
  1391.                         gr_set_bitmap_data(*bmp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next]);
  1392.                         Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w;
  1393.  
  1394. #ifndef MACDATA
  1395.                         switch (pigsize) {
  1396.                         default:
  1397.                                 if (!GameArg.EdiMacData)
  1398.                                         break;
  1399.                                 DXX_BOOST_FALLTHROUGH;
  1400.                         case MAC_ALIEN1_PIGSIZE:
  1401.                         case MAC_ALIEN2_PIGSIZE:
  1402.                         case MAC_FIRE_PIGSIZE:
  1403.                         case MAC_GROUPA_PIGSIZE:
  1404.                         case MAC_ICE_PIGSIZE:
  1405.                         case MAC_WATER_PIGSIZE:
  1406.                                 swap_0_255(*bmp);
  1407.                                 break;
  1408.                         }
  1409. #endif
  1410. #endif
  1411.                 }
  1412.  
  1413.                 //@@if ( bmp->bm_selector ) {
  1414.                 //@@#if !defined(WINDOWS) && !defined(MACINTOSH)
  1415.                 //@@    if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
  1416.                 //@@            Error( "Error modifying selector base in piggy.c\n" );
  1417.                 //@@#endif
  1418.                 //@@}
  1419.  
  1420.                 compute_average_rgb(bmp, bmp->avg_color_rgb);
  1421.  
  1422.         }
  1423.  
  1424.         if (CGameArg.SysLowMem)
  1425.         {
  1426.                 if ( org_i != i )
  1427.                         GameBitmaps[org_i] = GameBitmaps[i];
  1428.         }
  1429.  
  1430. //@@Removed from John's code:
  1431. //@@#ifndef WINDOWS
  1432. //@@    if ( bmp->bm_selector ) {
  1433. //@@            if (!dpmi_modify_selector_base( bmp->bm_selector, bmp->bm_data ))
  1434. //@@                    Error( "Error modifying selector base in piggy.c\n" );
  1435. //@@    }
  1436. //@@#endif
  1437.  
  1438. }
  1439. }
  1440.  
  1441. namespace dsx {
  1442. void piggy_bitmap_page_out_all()
  1443. {
  1444.         int i;
  1445.        
  1446.         Piggy_bitmap_cache_next = 0;
  1447.  
  1448.         texmerge_flush();
  1449.         rle_cache_flush();
  1450.  
  1451.         for (i=0; i<Num_bitmap_files; i++ ) {
  1452.                 if ( GameBitmapOffset[i] > 0 ) {        // Don't page out bitmaps read from disk!!!
  1453.                         GameBitmaps[i].set_flags(BM_FLAG_PAGED_OUT);
  1454.                         gr_set_bitmap_data(GameBitmaps[i], nullptr);
  1455.                 }
  1456.         }
  1457.  
  1458. }
  1459. }
  1460.  
  1461. void piggy_load_level_data()
  1462. {
  1463.         piggy_bitmap_page_out_all();
  1464.         paging_touch_all(Vclip);
  1465. }
  1466.  
  1467. #if defined(DXX_BUILD_DESCENT_II)
  1468. #if DXX_USE_EDITOR
  1469.  
  1470. static void piggy_write_pigfile(const char *filename)
  1471. {
  1472.         int bitmap_data_start, data_offset;
  1473.         DiskBitmapHeader bmh;
  1474.         int org_offset;
  1475.         char subst_name[32];
  1476.         int i;
  1477.         char tname[FILENAME_LEN];
  1478.  
  1479.         for (i=0; i < Num_bitmap_files; i++ ) {
  1480.                 bitmap_index bi;
  1481.                 bi.index = i;
  1482.                 PIGGY_PAGE_IN( bi );
  1483.         }
  1484.  
  1485.         piggy_close_file();
  1486.  
  1487.         auto pig_fp = PHYSFSX_openWriteBuffered(filename);       //open PIG file
  1488.         Assert(pig_fp);
  1489.  
  1490.         write_int(PIGFILE_ID,pig_fp);
  1491.         write_int(PIGFILE_VERSION,pig_fp);
  1492.  
  1493.         Num_bitmap_files--;
  1494.         PHYSFS_write( pig_fp, &Num_bitmap_files, sizeof(int), 1 );
  1495.         Num_bitmap_files++;
  1496.  
  1497.         bitmap_data_start = PHYSFS_tell(pig_fp);
  1498.         bitmap_data_start += (Num_bitmap_files - 1) * sizeof(DiskBitmapHeader);
  1499.         data_offset = bitmap_data_start;
  1500.  
  1501.         change_filename_extension(tname,filename,"lst");
  1502.         auto fp1 = PHYSFSX_openWriteBuffered(tname);
  1503.         change_filename_extension(tname,filename,"all");
  1504.         auto fp2 = PHYSFSX_openWriteBuffered(tname);
  1505.  
  1506.         for (i=1; i < Num_bitmap_files; i++ ) {
  1507.                 grs_bitmap *bmp;
  1508.  
  1509.                 const auto name = AllBitmaps[i].name.data();
  1510.                 {
  1511.                         char *p1;
  1512.                         if (const auto p = strchr(name, '#')) {   // this is an ABM == animated bitmap
  1513.                                 int n;
  1514.                                 p1 = p; p1++;
  1515.                                 n = atoi(p1);
  1516.                                 *p = 0;
  1517.                                 if (fp2 && n==0)
  1518.                                         PHYSFSX_printf( fp2, "%s.abm\n", name);
  1519.                                 memcpy(bmh.name, name, 8);
  1520.                                 Assert( n <= DBM_NUM_FRAMES );
  1521.                                 bmh.dflags = DBM_FLAG_ABM + n;
  1522.                                 *p = '#';
  1523.                         } else {
  1524.                                 if (fp2)
  1525.                                         PHYSFSX_printf( fp2, "%s.bbm\n", name);
  1526.                                 memcpy(bmh.name, name, 8);
  1527.                                 bmh.dflags = 0;
  1528.                         }
  1529.                 }
  1530.                 bmp = &GameBitmaps[i];
  1531.  
  1532.                 assert(!bmp->get_flag_mask(BM_FLAG_PAGED_OUT));
  1533.  
  1534.                 if (fp1)
  1535.                         PHYSFSX_printf(fp1, "BMP: %s, size %d bytes", name, bmp->bm_rowsize * bmp->bm_h);
  1536.                 org_offset = PHYSFS_tell(pig_fp);
  1537.                 bmh.offset = data_offset - bitmap_data_start;
  1538.                 PHYSFSX_fseek( pig_fp, data_offset, SEEK_SET );
  1539.  
  1540.                 if (bmp->get_flag_mask(BM_FLAG_RLE))
  1541.                 {
  1542.                         const auto size = reinterpret_cast<const int *>(bmp->bm_data);
  1543.                         PHYSFS_write( pig_fp, bmp->bm_data, sizeof(ubyte), *size );
  1544.                         data_offset += *size;
  1545.                         if (fp1)
  1546.                                 PHYSFSX_printf( fp1, ", and is already compressed to %d bytes.\n", *size );
  1547.                 } else {
  1548.                         PHYSFS_write( pig_fp, bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h );
  1549.                         data_offset += bmp->bm_rowsize * bmp->bm_h;
  1550.                         if (fp1)
  1551.                                 PHYSFSX_printf( fp1, ".\n" );
  1552.                 }
  1553.                 PHYSFSX_fseek( pig_fp, org_offset, SEEK_SET );
  1554.                 Assert( GameBitmaps[i].bm_w < 4096 );
  1555.                 bmh.width = (GameBitmaps[i].bm_w & 0xff);
  1556.                 bmh.wh_extra = ((GameBitmaps[i].bm_w >> 8) & 0x0f);
  1557.                 Assert( GameBitmaps[i].bm_h < 4096 );
  1558.                 bmh.height = GameBitmaps[i].bm_h;
  1559.                 bmh.wh_extra |= ((GameBitmaps[i].bm_h >> 4) & 0xf0);
  1560.                 bmh.flags = GameBitmaps[i].get_flags();
  1561.                 if (piggy_is_substitutable_bitmap(name, subst_name))
  1562.                 {
  1563.                         bitmap_index other_bitmap;
  1564.                         other_bitmap = piggy_find_bitmap( subst_name );
  1565.                         GameBitmapXlat[i] = other_bitmap.index;
  1566.                         bmh.flags |= BM_FLAG_PAGED_OUT;
  1567.                 } else {
  1568.                         bmh.flags &= ~BM_FLAG_PAGED_OUT;
  1569.                 }
  1570.                 bmh.avg_color = compute_average_pixel(&GameBitmaps[i]);
  1571.                 PHYSFS_write(pig_fp, &bmh, sizeof(DiskBitmapHeader), 1);        // Mark as a bitmap
  1572.         }
  1573.         PHYSFSX_printf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files );
  1574. }
  1575.  
  1576. static void write_int(int i, PHYSFS_File *file)
  1577. {
  1578.         if (PHYSFS_write( file, &i, sizeof(i), 1) != 1)
  1579.                 Error( "Error reading int in gamesave.c" );
  1580.  
  1581. }
  1582. #endif
  1583. #endif
  1584.  
  1585. namespace dsx {
  1586. void piggy_close()
  1587. {
  1588.         int i;
  1589.  
  1590. #if defined(DXX_BUILD_DESCENT_I)
  1591.         custom_close();
  1592. #endif
  1593.         piggy_close_file();
  1594.         BitmapBits.reset();
  1595.         SoundBits.reset();
  1596.         for (i = 0; i < Num_sound_files; i++)
  1597.                 if (SoundOffset[i] == 0)
  1598.                         d_free(GameSounds[i].data);
  1599. #if defined(DXX_BUILD_DESCENT_II)
  1600.         free_bitmap_replacements();
  1601.         free_d1_tmap_nums();
  1602. #endif
  1603. }
  1604. }
  1605.  
  1606. void remove_char( char * s, char c )
  1607. {
  1608.         char *p = strchr(s,c);
  1609.         if (p) *p = '\0';
  1610. }
  1611.  
  1612. #if defined(DXX_BUILD_DESCENT_II)
  1613. #if DXX_USE_EDITOR
  1614. static const BitmapFile *piggy_does_bitmap_exist_slow(const char *const name)
  1615. {
  1616.         range_for (auto &i, partial_const_range(AllBitmaps, Num_bitmap_files))
  1617.         {
  1618.                 if (!strcmp(i.name.data(), name))
  1619.                         return &i;
  1620.         }
  1621.         return nullptr;
  1622. }
  1623.  
  1624.  
  1625. constexpr char gauge_bitmap_names[][9] = {
  1626.         "gauge01",
  1627.         "gauge02",
  1628.         "gauge06",
  1629.         "targ01",
  1630.         "targ02",
  1631.         "targ03",
  1632.         "targ04",
  1633.         "targ05",
  1634.         "targ06",
  1635.         "gauge18",
  1636. #if defined(DXX_BUILD_DESCENT_I)
  1637.         "targ01pc",
  1638.         "targ02pc",
  1639.         "targ03pc",
  1640.         "gaug18pc"
  1641. #elif defined(DXX_BUILD_DESCENT_II)
  1642.         "gauge01b",
  1643.         "gauge02b",
  1644.         "gauge06b",
  1645.         "targ01b",
  1646.         "targ02b",
  1647.         "targ03b",
  1648.         "targ04b",
  1649.         "targ05b",
  1650.         "targ06b",
  1651.         "gauge18b",
  1652.         "gauss1",
  1653.         "helix1",
  1654.         "phoenix1"
  1655. #endif
  1656. };
  1657.  
  1658. static const char (*piggy_is_gauge_bitmap(const char *const base_name))[9]
  1659. {
  1660.         range_for (auto &i, gauge_bitmap_names)
  1661.         {
  1662.                 if (!d_stricmp(base_name, i))
  1663.                         return &i;
  1664.         }
  1665.         return nullptr;
  1666. }
  1667.  
  1668. static int piggy_is_substitutable_bitmap(char * name, char (&subst_name)[32])
  1669. {
  1670.         int frame;
  1671.         char * p;
  1672.         char base_name[ 16 ];
  1673.        
  1674.         strcpy( subst_name, name );
  1675.         p = strchr( subst_name, '#' );
  1676.         if ( p ) {
  1677.                 frame = atoi( &p[1] );
  1678.                 *p = 0;
  1679.                 strcpy( base_name, subst_name );
  1680.                 if ( !piggy_is_gauge_bitmap( base_name )) {
  1681.                         snprintf(subst_name, sizeof(subst_name), "%s#%d", base_name, frame + 1);
  1682.                         if ( piggy_does_bitmap_exist_slow( subst_name )  ) {
  1683.                                 if ( frame & 1 ) {
  1684.                                         snprintf(subst_name, sizeof(subst_name), "%s#%d", base_name, frame - 1);
  1685.                                         return 1;
  1686.                                 }
  1687.                         }
  1688.                 }
  1689.         }
  1690.         strcpy( subst_name, name );
  1691.         return 0;
  1692. }
  1693. #endif
  1694.  
  1695.  
  1696. /*
  1697.  * Functions for loading replacement textures
  1698.  *  1) From .pog files
  1699.  *  2) From descent.pig (for loading d1 levels)
  1700.  */
  1701.  
  1702. static void free_bitmap_replacements()
  1703. {
  1704.         Bitmap_replacement_data.reset();
  1705. }
  1706.  
  1707. void load_bitmap_replacements(const char *level_name)
  1708. {
  1709.         char ifile_name[FILENAME_LEN];
  1710.         //first, free up data allocated for old bitmaps
  1711.         free_bitmap_replacements();
  1712.  
  1713.         change_filename_extension(ifile_name, level_name, ".POG" );
  1714.         if (auto ifile = PHYSFSX_openReadBuffered(ifile_name))
  1715.         {
  1716.                 int id,version;
  1717.                 unsigned n_bitmaps;
  1718.                 int bitmap_data_size;
  1719.  
  1720.                 id = PHYSFSX_readInt(ifile);
  1721.                 version = PHYSFSX_readInt(ifile);
  1722.  
  1723.                 if (id != MAKE_SIG('G','O','P','D') || version != 1) {
  1724.                         return;
  1725.                 }
  1726.  
  1727.                 n_bitmaps = PHYSFSX_readInt(ifile);
  1728.  
  1729.                 RAIIdmem<uint16_t[]> indices;
  1730.                 MALLOC( indices, uint16_t[], n_bitmaps );
  1731.  
  1732.                 range_for (auto &i, unchecked_partial_range(indices.get(), n_bitmaps))
  1733.                         i = PHYSFSX_readShort(ifile);
  1734.  
  1735.                 bitmap_data_size = PHYSFS_fileLength(ifile) - PHYSFS_tell(ifile) - sizeof(DiskBitmapHeader) * n_bitmaps;
  1736.                 Bitmap_replacement_data = std::make_unique<ubyte[]>(bitmap_data_size);
  1737.  
  1738.                 range_for (const auto i, unchecked_partial_range(indices.get(), n_bitmaps))
  1739.                 {
  1740.                         DiskBitmapHeader bmh;
  1741.                         grs_bitmap *bm = &GameBitmaps[i];
  1742.                         int width;
  1743.  
  1744.                         DiskBitmapHeader_read(&bmh, ifile);
  1745.  
  1746.                         width = bmh.width + (static_cast<short>(bmh.wh_extra & 0x0f) << 8);
  1747.                         gr_set_bitmap_data(*bm, NULL);  // free ogl texture
  1748.                         gr_init_bitmap(*bm, bm_mode::linear, 0, 0, width, bmh.height + (static_cast<short>(bmh.wh_extra & 0xf0) << 4), width, NULL);
  1749. #if !DXX_USE_OGL
  1750.                         bm->avg_color = bmh.avg_color;
  1751. #endif
  1752.                         bm->bm_data = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(bmh.offset));
  1753.  
  1754.                         gr_set_bitmap_flags(*bm, bmh.flags & BM_FLAGS_TO_COPY);
  1755.  
  1756.                         GameBitmapOffset[i] = 0; // don't try to read bitmap from current pigfile
  1757.                 }
  1758.  
  1759.                 PHYSFS_read(ifile,Bitmap_replacement_data,1,bitmap_data_size);
  1760.  
  1761.                 range_for (const auto i, unchecked_partial_range(indices.get(), n_bitmaps))
  1762.                 {
  1763.                         grs_bitmap *bm = &GameBitmaps[i];
  1764.                         gr_set_bitmap_data(*bm, &Bitmap_replacement_data[reinterpret_cast<uintptr_t>(bm->bm_data)]);
  1765.                 }
  1766.                 last_palette_loaded_pig[0]= 0;  //force pig re-load
  1767.                 texmerge_flush();       //for re-merging with new textures
  1768.         }
  1769. }
  1770.  
  1771. /* calculate table to translate d1 bitmaps to current palette,
  1772.  * return -1 on error
  1773.  */
  1774. static int get_d1_colormap(palette_array_t &d1_palette, std::array<color_palette_index, 256> &colormap)
  1775. {
  1776.         auto palette_file = PHYSFSX_openReadBuffered(D1_PALETTE);
  1777.         if (!palette_file || PHYSFS_fileLength(palette_file) != 9472)
  1778.                 return -1;
  1779.         PHYSFS_read( palette_file, &d1_palette[0], sizeof(d1_palette[0]), d1_palette.size() );
  1780.         build_colormap_good(d1_palette, colormap);
  1781.         // don't change transparencies:
  1782.         colormap[254] = color_palette_index{254};
  1783.         colormap[255] = TRANSPARENCY_COLOR;
  1784.         return 0;
  1785. }
  1786.  
  1787. #define JUST_IN_CASE 132 /* is enough for d1 pc registered */
  1788. static void bitmap_read_d1( grs_bitmap *bitmap, /* read into this bitmap */
  1789.                      PHYSFS_File *d1_Piggy_fp, /* read from this file */
  1790.                      int bitmap_data_start, /* specific to file */
  1791.                      DiskBitmapHeader *bmh, /* header info for bitmap */
  1792.                      uint8_t **next_bitmap, /* where to write it (if 0, use malloc) */
  1793.                                          palette_array_t &d1_palette, /* what palette the bitmap has */
  1794.                                          std::array<color_palette_index, 256> &colormap) /* how to translate bitmap's colors */
  1795. {
  1796.         int zsize, pigsize = PHYSFS_fileLength(d1_Piggy_fp);
  1797.         uint8_t *data;
  1798.         int width;
  1799.  
  1800.         width = bmh->width + (static_cast<short>(bmh->wh_extra & 0x0f) << 8);
  1801.         gr_set_bitmap_data(*bitmap, NULL);      // free ogl texture
  1802.         gr_init_bitmap(*bitmap, bm_mode::linear, 0, 0, width, bmh->height + (static_cast<short>(bmh->wh_extra & 0xf0) << 4), width, NULL);
  1803. #if !DXX_USE_OGL
  1804.         bitmap->avg_color = bmh->avg_color;
  1805. #endif
  1806.         gr_set_bitmap_flags(*bitmap, bmh->flags & BM_FLAGS_TO_COPY);
  1807.  
  1808.         PHYSFSX_fseek(d1_Piggy_fp, bitmap_data_start + bmh->offset, SEEK_SET);
  1809.         if (bmh->flags & BM_FLAG_RLE) {
  1810.                 zsize = PHYSFSX_readInt(d1_Piggy_fp);
  1811.                 PHYSFSX_fseek(d1_Piggy_fp, -4, SEEK_CUR);
  1812.         } else
  1813.                 zsize = bitmap->bm_h * bitmap->bm_w;
  1814.  
  1815.         if (next_bitmap) {
  1816.                 data = *next_bitmap;
  1817.                 *next_bitmap += zsize;
  1818.         } else {
  1819.                 MALLOC(data, ubyte, zsize + JUST_IN_CASE);
  1820.         }
  1821.         if (!data) return;
  1822.  
  1823.         PHYSFS_read(d1_Piggy_fp, data, 1, zsize);
  1824.         gr_set_bitmap_data(*bitmap, data);
  1825.         switch(pigsize) {
  1826.         case D1_MAC_PIGSIZE:
  1827.         case D1_MAC_SHARE_PIGSIZE:
  1828.                 if (bmh->flags & BM_FLAG_RLE)
  1829.                         rle_swap_0_255(*bitmap);
  1830.                 else
  1831.                         swap_0_255(*bitmap);
  1832.         }
  1833.         if (bmh->flags & BM_FLAG_RLE)
  1834.                 rle_remap(*bitmap, colormap);
  1835.         else
  1836.                 gr_remap_bitmap_good(*bitmap, d1_palette, TRANSPARENCY_COLOR, -1);
  1837.         if (bmh->flags & BM_FLAG_RLE) { // size of bitmap could have changed!
  1838.                 int new_size;
  1839.                 memcpy(&new_size, bitmap->bm_data, 4);
  1840.                 if (next_bitmap) {
  1841.                         *next_bitmap += new_size - zsize;
  1842.                 } else {
  1843.                         Assert( zsize + JUST_IN_CASE >= new_size );
  1844.                         bitmap->bm_mdata = reinterpret_cast<uint8_t *>(d_realloc(bitmap->bm_mdata, new_size));
  1845.                         Assert(bitmap->bm_data);
  1846.                 }
  1847.         }
  1848. }
  1849.  
  1850. #define D1_MAX_TEXTURES 800
  1851. #define D1_MAX_TMAP_NUM 1630 // 1621 in descent.pig Mac registered
  1852.  
  1853. /* the inverse of the d2 Textures array, but for the descent 1 pigfile.
  1854.  * "Textures" looks up a d2 bitmap index given a d2 tmap_num.
  1855.  * "d1_tmap_nums" looks up a d1 tmap_num given a d1 bitmap. "-1" means "None".
  1856.  */
  1857. using d1_tmap_nums_t = std::array<short, D1_MAX_TMAP_NUM>;
  1858. static std::unique_ptr<d1_tmap_nums_t> d1_tmap_nums;
  1859.  
  1860. static void free_d1_tmap_nums() {
  1861.         d1_tmap_nums.reset();
  1862. }
  1863.  
  1864. static void bm_read_d1_tmap_nums(PHYSFS_File *d1pig)
  1865. {
  1866.         int i, d1_index;
  1867.  
  1868.         PHYSFSX_fseek(d1pig, 8, SEEK_SET);
  1869.         d1_tmap_nums = std::make_unique<d1_tmap_nums_t>();
  1870.         d1_tmap_nums->fill(-1);
  1871.         for (i = 0; i < D1_MAX_TEXTURES; i++) {
  1872.                 d1_index = PHYSFSX_readShort(d1pig);
  1873.                 Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
  1874.                 (*d1_tmap_nums)[d1_index] = i;
  1875.                 if (PHYSFS_eof(d1pig))
  1876.                         break;
  1877.         }
  1878. }
  1879.  
  1880. // this function is at the same position in the d1 shareware piggy loading
  1881. // algorithm as bm_load_sub in main/bmread.c
  1882. static int get_d1_bm_index(char *filename, PHYSFS_File *d1_pig) {
  1883.         int i, N_bitmaps;
  1884.         DiskBitmapHeader bmh;
  1885.         if (strchr (filename, '.'))
  1886.                 *strchr (filename, '.') = '\0'; // remove extension
  1887.         PHYSFSX_fseek (d1_pig, 0, SEEK_SET);
  1888.         N_bitmaps = PHYSFSX_readInt (d1_pig);
  1889.         PHYSFSX_fseek (d1_pig, 8, SEEK_SET);
  1890.         for (i = 1; i <= N_bitmaps; i++) {
  1891.                 DiskBitmapHeader_d1_read(&bmh, d1_pig);
  1892.                 if (!d_strnicmp(bmh.name, filename, 8))
  1893.                         return i;
  1894.         }
  1895.         return -1;
  1896. }
  1897.  
  1898. // imitate the algorithm of gamedata_read_tbl in main/bmread.c
  1899. static void read_d1_tmap_nums_from_hog(PHYSFS_File *d1_pig)
  1900. {
  1901. #define LINEBUF_SIZE 600
  1902.         int reading_textures = 0;
  1903.         short texture_count = 0;
  1904.         int bitmaps_tbl_is_binary = 0;
  1905.         int i;
  1906.  
  1907.         auto bitmaps = PHYSFSX_openReadBuffered("bitmaps.tbl");
  1908.         if (!bitmaps) {
  1909.                 bitmaps = PHYSFSX_openReadBuffered ("bitmaps.bin");
  1910.                 bitmaps_tbl_is_binary = 1;
  1911.         }
  1912.  
  1913.         if (!bitmaps) {
  1914.                 Warning ("Could not find bitmaps.* for reading d1 textures");
  1915.                 return;
  1916.         }
  1917.  
  1918.         d1_tmap_nums = std::make_unique<d1_tmap_nums_t>();
  1919.         d1_tmap_nums->fill(-1);
  1920.  
  1921.         for (PHYSFSX_gets_line_t<LINEBUF_SIZE> inputline; PHYSFSX_fgets (inputline, bitmaps);)
  1922.         {
  1923.                 char *arg;
  1924.  
  1925.                 if (bitmaps_tbl_is_binary)
  1926.                         decode_text_line((inputline));
  1927.                 else
  1928.                         while (inputline[(i=strlen(inputline))-2]=='\\')
  1929.                                 PHYSFSX_fgets(inputline,bitmaps,i-2); // strip comments
  1930.                 REMOVE_EOL(inputline);
  1931.                 if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline);
  1932.                 if (strlen(inputline) == LINEBUF_SIZE-1) {
  1933.                         Warning("Possible line truncation in BITMAPS.TBL");
  1934.                         return;
  1935.                 }
  1936.                 arg = strtok( inputline, space_tab );
  1937.                 if (arg && arg[0] == '@') {
  1938.                         arg++;
  1939.                         //Registered_only = 1;
  1940.                 }
  1941.  
  1942.                 while (arg != NULL) {
  1943.                         if (*arg == '$')
  1944.                                 reading_textures = 0; // default
  1945.                         if (!strcmp(arg, "$TEXTURES")) // BM_TEXTURES
  1946.                                 reading_textures = 1;
  1947.                         else if (! d_stricmp(arg, "$ECLIP") // BM_ECLIP
  1948.                                    || ! d_stricmp(arg, "$WCLIP")) // BM_WCLIP
  1949.                                         texture_count++;
  1950.                         else // not a special token, must be a bitmap!
  1951.                                 if (reading_textures) {
  1952.                                         while (*arg == '\t' || *arg == ' ')
  1953.                                                 arg++;//remove unwanted blanks
  1954.                                         if (*arg == '\0')
  1955.                                                 break;
  1956.                                         if (d1_tmap_num_unique(texture_count)) {
  1957.                                                 int d1_index = get_d1_bm_index(arg, d1_pig);
  1958.                                                 if (d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM) {
  1959.                                                         (*d1_tmap_nums)[d1_index] = texture_count;
  1960.                                                         //int d2_index = d2_index_for_d1_index(d1_index);
  1961.                                                 }
  1962.                                 }
  1963.                                 Assert (texture_count < D1_MAX_TEXTURES);
  1964.                                 texture_count++;
  1965.                         }
  1966.  
  1967.                         arg = strtok (NULL, equal_space);
  1968.                 }
  1969.         }
  1970. }
  1971.  
  1972. /* If the given d1_index is the index of a bitmap we have to load
  1973.  * (because it is unique to descent 1), then returns the d2_index that
  1974.  * the given d1_index replaces.
  1975.  * Returns -1 if the given d1_index is not unique to descent 1.
  1976.  */
  1977. static short d2_index_for_d1_index(short d1_index)
  1978. {
  1979.         Assert(d1_index >= 0 && d1_index < D1_MAX_TMAP_NUM);
  1980.         if (! d1_tmap_nums || (*d1_tmap_nums)[d1_index] == -1
  1981.             || ! d1_tmap_num_unique((*d1_tmap_nums)[d1_index]))
  1982.                 return -1;
  1983.  
  1984.         return Textures[convert_d1_tmap_num((*d1_tmap_nums)[d1_index])].index;
  1985. }
  1986.  
  1987. #define D1_BITMAPS_SIZE 300000
  1988. void load_d1_bitmap_replacements()
  1989. {
  1990.         DiskBitmapHeader bmh;
  1991.         int pig_data_start, bitmap_header_start, bitmap_data_start;
  1992.         int N_bitmaps;
  1993.         short d1_index, d2_index;
  1994.         uint8_t * next_bitmap;
  1995.         palette_array_t d1_palette;
  1996.         char *p;
  1997.         int pigsize;
  1998.  
  1999.         auto d1_Piggy_fp = PHYSFSX_openReadBuffered(D1_PIGFILE);
  2000.  
  2001. #define D1_PIG_LOAD_FAILED "Failed loading " D1_PIGFILE
  2002.         if (!d1_Piggy_fp) {
  2003.                 Warning(D1_PIG_LOAD_FAILED);
  2004.                 return;
  2005.         }
  2006.  
  2007.         //first, free up data allocated for old bitmaps
  2008.         free_bitmap_replacements();
  2009.  
  2010.         std::array<color_palette_index, 256> colormap;
  2011.         if (get_d1_colormap( d1_palette, colormap ) != 0)
  2012.                 Warning("Could not load descent 1 color palette");
  2013.  
  2014.         pigsize = PHYSFS_fileLength(d1_Piggy_fp);
  2015.         switch (pigsize) {
  2016.         case D1_SHARE_BIG_PIGSIZE:
  2017.         case D1_SHARE_10_PIGSIZE:
  2018.         case D1_SHARE_PIGSIZE:
  2019.         case D1_10_BIG_PIGSIZE:
  2020.         case D1_10_PIGSIZE:
  2021.                 pig_data_start = 0;
  2022.                 // OK, now we need to read d1_tmap_nums by emulating d1's gamedata_read_tbl()
  2023.                 read_d1_tmap_nums_from_hog(d1_Piggy_fp);
  2024.                 break;
  2025.         default:
  2026.                 Warning("Unknown size for " D1_PIGFILE);
  2027.                 Int3();
  2028.                 DXX_BOOST_FALLTHROUGH;
  2029.         case D1_PIGSIZE:
  2030.         case D1_OEM_PIGSIZE:
  2031.         case D1_MAC_PIGSIZE:
  2032.         case D1_MAC_SHARE_PIGSIZE:
  2033.                 pig_data_start = PHYSFSX_readInt(d1_Piggy_fp );
  2034.                 bm_read_d1_tmap_nums(d1_Piggy_fp); //was: bm_read_all_d1(fp);
  2035.                 //for (i = 0; i < 1800; i++) GameBitmapXlat[i] = PHYSFSX_readShort(d1_Piggy_fp);
  2036.                 break;
  2037.         }
  2038.  
  2039.         PHYSFSX_fseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
  2040.         N_bitmaps = PHYSFSX_readInt(d1_Piggy_fp);
  2041.         {
  2042.                 int N_sounds = PHYSFSX_readInt(d1_Piggy_fp);
  2043.                 int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
  2044.                         + N_sounds * sizeof(DiskSoundHeader);
  2045.                 bitmap_header_start = pig_data_start + 2 * sizeof(int);
  2046.                 bitmap_data_start = bitmap_header_start + header_size;
  2047.         }
  2048.  
  2049.         Bitmap_replacement_data = std::make_unique<ubyte[]>(D1_BITMAPS_SIZE);
  2050.         if (!Bitmap_replacement_data) {
  2051.                 Warning(D1_PIG_LOAD_FAILED);
  2052.                 return;
  2053.         }
  2054.  
  2055.         next_bitmap = Bitmap_replacement_data.get();
  2056.  
  2057.         for (d1_index = 1; d1_index <= N_bitmaps; d1_index++ ) {
  2058.                 d2_index = d2_index_for_d1_index(d1_index);
  2059.                 // only change bitmaps which are unique to d1
  2060.                 if (d2_index != -1) {
  2061.                         PHYSFSX_fseek(d1_Piggy_fp, bitmap_header_start + (d1_index-1) * DISKBITMAPHEADER_D1_SIZE, SEEK_SET);
  2062.                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
  2063.  
  2064.                         bitmap_read_d1( &GameBitmaps[d2_index], d1_Piggy_fp, bitmap_data_start, &bmh, &next_bitmap, d1_palette, colormap );
  2065.                         Assert(next_bitmap - Bitmap_replacement_data.get() < D1_BITMAPS_SIZE);
  2066.                         GameBitmapOffset[d2_index] = 0; // don't try to read bitmap from current d2 pigfile
  2067.                         GameBitmapFlags[d2_index] = bmh.flags;
  2068.  
  2069.                         auto &abname = AllBitmaps[d2_index].name;
  2070.                         if ((p = strchr(abname.data(), '#')) /* d2 BM is animated */
  2071.                              && !(bmh.dflags & DBM_FLAG_ABM) ) { /* d1 bitmap is not animated */
  2072.                                 int i, len = p - abname.data();
  2073.                                 for (i = 0; i < Num_bitmap_files; i++)
  2074.                                         if (i != d2_index && ! memcmp(abname.data(), AllBitmaps[i].name.data(), len))
  2075.                                         {
  2076.                                                 gr_set_bitmap_data(GameBitmaps[i], NULL);       // free ogl texture
  2077.                                                 GameBitmaps[i] = GameBitmaps[d2_index];
  2078.                                                 GameBitmapOffset[i] = 0;
  2079.                                                 GameBitmapFlags[i] = bmh.flags;
  2080.                                         }
  2081.                         }
  2082.                 }
  2083.         }
  2084.         last_palette_loaded_pig[0]= 0;  //force pig re-load
  2085.  
  2086.         texmerge_flush();       //for re-merging with new textures
  2087. }
  2088.  
  2089.  
  2090. /*
  2091.  * Find and load the named bitmap from descent.pig
  2092.  * similar to read_extra_bitmap_iff
  2093.  */
  2094. bitmap_index read_extra_bitmap_d1_pig(const char *name)
  2095. {
  2096.         bitmap_index bitmap_num;
  2097.         grs_bitmap * n = &GameBitmaps[extra_bitmap_num];
  2098.  
  2099.         bitmap_num.index = 0;
  2100.  
  2101.         {
  2102.                 int pig_data_start, bitmap_header_start, bitmap_data_start;
  2103.                 int N_bitmaps;
  2104.                 palette_array_t d1_palette;
  2105.                 int pigsize;
  2106.                 auto d1_Piggy_fp = PHYSFSX_openReadBuffered(D1_PIGFILE);
  2107.                 if (!d1_Piggy_fp)
  2108.                 {
  2109.                         Warning(D1_PIG_LOAD_FAILED);
  2110.                         return bitmap_num;
  2111.                 }
  2112.  
  2113.                 std::array<color_palette_index, 256> colormap;
  2114.                 if (get_d1_colormap( d1_palette, colormap ) != 0)
  2115.                         Warning("Could not load descent 1 color palette");
  2116.  
  2117.                 pigsize = PHYSFS_fileLength(d1_Piggy_fp);
  2118.                 switch (pigsize) {
  2119.                 case D1_SHARE_BIG_PIGSIZE:
  2120.                 case D1_SHARE_10_PIGSIZE:
  2121.                 case D1_SHARE_PIGSIZE:
  2122.                 case D1_10_BIG_PIGSIZE:
  2123.                 case D1_10_PIGSIZE:
  2124.                         pig_data_start = 0;
  2125.                         break;
  2126.                 default:
  2127.                         Warning("Unknown size for " D1_PIGFILE);
  2128.                         Int3();
  2129.                         DXX_BOOST_FALLTHROUGH;
  2130.                 case D1_PIGSIZE:
  2131.                 case D1_OEM_PIGSIZE:
  2132.                 case D1_MAC_PIGSIZE:
  2133.                 case D1_MAC_SHARE_PIGSIZE:
  2134.                         pig_data_start = PHYSFSX_readInt(d1_Piggy_fp );
  2135.  
  2136.                         break;
  2137.                 }
  2138.  
  2139.                 PHYSFSX_fseek( d1_Piggy_fp, pig_data_start, SEEK_SET );
  2140.                 N_bitmaps = PHYSFSX_readInt(d1_Piggy_fp);
  2141.                 {
  2142.                         int N_sounds = PHYSFSX_readInt(d1_Piggy_fp);
  2143.                         int header_size = N_bitmaps * DISKBITMAPHEADER_D1_SIZE
  2144.                                 + N_sounds * sizeof(DiskSoundHeader);
  2145.                         bitmap_header_start = pig_data_start + 2 * sizeof(int);
  2146.                         bitmap_data_start = bitmap_header_start + header_size;
  2147.                 }
  2148.  
  2149.                 for (unsigned i = 1;; ++i)
  2150.                 {
  2151.                         if (i > N_bitmaps)
  2152.                         {
  2153.                                 con_printf(CON_DEBUG, "could not find bitmap %s", name);
  2154.                                 return bitmap_num;
  2155.                         }
  2156.                         DiskBitmapHeader bmh;
  2157.                         DiskBitmapHeader_d1_read(&bmh, d1_Piggy_fp);
  2158.                         if (!d_strnicmp(bmh.name, name, 8))
  2159.                         {
  2160.                                 bitmap_read_d1(n, d1_Piggy_fp, bitmap_data_start, &bmh, 0, d1_palette, colormap);
  2161.                                 break;
  2162.                         }
  2163.                 }
  2164.         }
  2165.  
  2166. #if !DXX_USE_OGL
  2167.         n->avg_color = 0;       //compute_average_pixel(n);
  2168. #endif
  2169.  
  2170.         bitmap_num.index = extra_bitmap_num;
  2171.  
  2172.         GameBitmaps[extra_bitmap_num++] = *n;
  2173.  
  2174.         return bitmap_num;
  2175. }
  2176. #endif
  2177.  
  2178. /*
  2179.  * reads a bitmap_index structure from a PHYSFS_File
  2180.  */
  2181. void bitmap_index_read(PHYSFS_File *fp, bitmap_index &bi)
  2182. {
  2183.         bi.index = PHYSFSX_readShort(fp);
  2184. }
  2185.  
  2186. /*
  2187.  * reads n bitmap_index structs from a PHYSFS_File
  2188.  */
  2189. void bitmap_index_read_n(PHYSFS_File *fp, const partial_range_t<bitmap_index *> r)
  2190. {
  2191.         range_for (auto &i, r)
  2192.                 i.index = PHYSFSX_readShort(fp);
  2193. }
  2194.