Advertisement
Guest User

btddump.cpp

a guest
Jun 27th, 2021
377
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 43.57 KB | None | 0 0
  1.  
  2. // Appalachia.btd file format:
  3. //
  4. // 0x00000000-0x00000003: "BTDB"
  5. // 0x00000004-0x00000007: (int32) 6, format version
  6. // 0x00000008-0x0000000B: (float) -700.0, mimimum height
  7. // 0x0000000C-0x0000000F: (float) 38209.996, maximum height
  8. // 0x00000010-0x00000013: (int32) 25728 (201 * 128), total resolution X
  9. // 0x00000014-0x00000017: (int32) 25728 (201 * 128), total resolution Y
  10. // 0x00000018-0x0000001B: (int32) -100, minimum cell X (west)
  11. // 0x0000001C-0x0000001F: (int32) -100, minimum cell Y (south)
  12. // 0x00000020-0x00000023: (int32) 100, maximum cell X (east)
  13. // 0x00000024-0x00000027: (int32) 100, maximum cell Y (north)
  14. // 0x00000028-0x0000002B: (int32) 43, number of land textures (LTEX records)
  15. // 0x0000002C-0x000000D7: 43 * int32, LTEX form IDs
  16. // 0x000000D8-0x0004EF5F: 201 * 201 * float[2], min, max height for each cell
  17. // 0x0004EF60-0x0018A97F: 201 * 2 * 201 * 2 * byte[8], cell quadrant land
  18. //                        textures (43 - LTEX_table_index, or zero if none)
  19. // 0x0018A980-0x0018A983: (int32) 30, number of ground covers (GCVR records)
  20. // 0x0018A984-0x0018A9FB: 30 * int32, GCVR form IDs
  21. // 0x0018A9FC-0x002C641B: 201 * 2 * 201 * 2 * byte[8], cell quadrant ground
  22. //                        covers (GCVR_table_index, or 0xFF if none)
  23. // 0x002C641C-0x007B4C9B: 201 * 8 * 201 * 8 * int16, LOD4 height map,
  24. //                        0 to 65535 maps to minimum height to maximum height
  25. // 0x007B4C9C-0x00CA351B: 201 * 8 * 201 * 8 * int16, LOD4 land textures,
  26. //                        bits[N * 3 to N * 3 + 2] = opacity of texture N,
  27. //                        texture 6 is the base texture
  28. // 0x00CA351C-0x01191D9B: 201 * 8 * 201 * 8 * int16, LOD4 normals (?),
  29. //                        Z6Y5X5 format (not sure)
  30. // 0x01191D9C-0x01250643: 97557 * (int32, int32), pairs of zlib compressed data
  31. //                        offset (relative to 0x01250644) and size
  32. // 0x01250644-EOF:        zlib compressed data blocks
  33. // zlib compressed blocks     0 to  1351 (26 * 26 * 2): LOD3, 8x8 cell groups
  34. //                         1352 to  6553 (51 * 51 * 2): LOD2, 4x4 cell groups
  35. //                         6554 to 16754   (101 * 101): LOD1, 2x2 cell groups
  36. //                        16755 to 57155   (201 * 201): LOD0 height map, LTEX
  37. //                        57156 to 97556   (201 * 201): LOD0 ground cover mask
  38. // LOD3, LOD2: pairs of height map, LTEX and normals blocks
  39. // LOD1: height map, land textures block only
  40. // height map, LTEX block format:
  41. //   0x0000-0x5FFF: 64 * (64, 128) int16, height map, only the samples
  42. //                  not present at lower levels of detail
  43. //   0x6000-0xBFFF: 64 * (64, 128) int16, land texture opacities
  44. // normals block format (LOD3 and LOD2 only):
  45. //   0x0000-0x5FFF: 64 * (64, 128) int16
  46. //   0x6000-0x7FFF: unused
  47. // ground cover block format (LOD0 only):
  48. //   0x0000-0x3FFF: 128 * 128 bytes, bit N is set if ground cover N is enabled
  49.  
  50. #include <cstdio>
  51. #include <cstdlib>
  52. #include <cstring>
  53. #include <cmath>
  54. #include <string>
  55. #include <vector>
  56. #include <set>
  57. #include <map>
  58. #include <algorithm>
  59. #include <exception>
  60. #include <stdexcept>
  61.  
  62. #if defined(_WIN32) || defined(_WIN64)
  63. extern "C"
  64. {
  65. // mman-win32 is required on Windows (https://github.com/alitrack/mman-win32)
  66. #  include "mman.c"
  67. }
  68. #else
  69. #  include <sys/mman.h>
  70. #endif
  71.  
  72. class ZLibDecompressor
  73. {
  74.  protected:
  75.   std::vector< unsigned char >  buf;
  76.   size_t  bufPos;
  77.   size_t  bufEnd;
  78.   const unsigned char *inPtr;
  79.   const unsigned char *inBufEnd;
  80.   unsigned int  sr;
  81.   unsigned int  srBitCnt;
  82.   inline unsigned char readU8()
  83.   {
  84.     if (inPtr >= inBufEnd)
  85.       throw std::runtime_error(std::string("end of ZLib compressed data"));
  86.     unsigned char c = *(inPtr++);
  87.     return c;
  88.   }
  89.   inline unsigned short readU16LE()
  90.   {
  91.     if ((inPtr + 1) >= inBufEnd)
  92.       throw std::runtime_error(std::string("end of ZLib compressed data"));
  93.     unsigned short  w = *(inPtr++);
  94.     w = w | ((unsigned short) *(inPtr++) << 8);
  95.     return w;
  96.   }
  97.   unsigned short readU16BE();
  98.   unsigned int readU32BE();
  99.   inline void srReset()
  100.   {
  101.     if (srBitCnt >= 8U)
  102.       inPtr--;
  103.     sr = 0x0000;
  104.     srBitCnt = 0;
  105.   }
  106.   // read bits packed in Deflate order (LSB first - LSB first)
  107.   // nBits must be in the range 1 to 16
  108.   unsigned int readBitsRR(unsigned char nBits);
  109.   // lenTbl[c] = length of symbol 'c' (0: not used)
  110.   static void huffmanBuildDecodeTable(
  111.       std::vector< unsigned int >& huffTable,
  112.       const std::vector< unsigned char >& lenTbl);
  113.   unsigned int huffmanDecode(const std::vector< unsigned int >& huffTable);
  114.  public:
  115.   ZLibDecompressor();
  116.   virtual ~ZLibDecompressor();
  117.   size_t decompressData(const unsigned char *inBuf,
  118.                         size_t compressedSize, size_t uncompressedSize);
  119.   inline size_t dataRemaining() const
  120.   {
  121.     return (bufEnd - bufPos);
  122.   }
  123.   inline unsigned char readByte()
  124.   {
  125.     unsigned char tmp = buf[bufPos];
  126.     bufPos++;
  127.     return tmp;
  128.   }
  129.   const unsigned char& operator[](size_t i) const
  130.   {
  131.     return *(&(buf.front()) + i);
  132.   }
  133.   void clear()
  134.   {
  135.     bufPos = 0;
  136.     bufEnd = 0;
  137.   }
  138. };
  139.  
  140. unsigned short ZLibDecompressor::readU16BE()
  141. {
  142.   unsigned short  w = readU8();
  143.   w = (w << 8) | readU8();
  144.   return w;
  145. }
  146.  
  147. unsigned int ZLibDecompressor::readU32BE()
  148. {
  149.   unsigned int  w = readU16BE();
  150.   w = (w << 16) | readU16BE();
  151.   return w;
  152. }
  153.  
  154. unsigned int ZLibDecompressor::readBitsRR(unsigned char nBits)
  155. {
  156.   unsigned int  w = 0;
  157.   unsigned char b = 0;
  158.   if (!srBitCnt)
  159.   {
  160.     sr = readU16LE();
  161.     srBitCnt = 16;
  162.   }
  163.   if (nBits > srBitCnt)
  164.   {
  165.     w = sr;
  166.     b = (unsigned char) srBitCnt;
  167.     nBits = nBits - (unsigned char) srBitCnt;
  168.     sr = readU16LE();
  169.     srBitCnt = 16;
  170.   }
  171.   w = w | ((sr & ((1U << nBits) - 1U)) << b);
  172.   sr = sr >> nBits;
  173.   srBitCnt = srBitCnt - nBits;
  174.   return w;
  175. }
  176.  
  177. void ZLibDecompressor::huffmanBuildDecodeTable(
  178.     std::vector< unsigned int >& huffTable,
  179.     const std::vector< unsigned char >& lenTbl)
  180. {
  181.   size_t  symCnt = 0;
  182.   for (size_t i = 0; i < lenTbl.size(); i++)
  183.     symCnt += size_t(bool(lenTbl[i]));
  184.   huffTable.resize(symCnt + 64);
  185.   symCnt = 0;
  186.   for (size_t i = 0; i < lenTbl.size(); i++)
  187.   {
  188.     if (lenTbl[i])
  189.     {
  190.       huffTable[symCnt + 64] =
  191.           (unsigned int) i | ((unsigned int) lenTbl[i] << 24);
  192.       symCnt++;
  193.     }
  194.   }
  195.   std::sort(huffTable.begin() + 64, huffTable.end());
  196.   for (size_t i = 0; i < 32; i++)
  197.   {
  198.     huffTable[i] = 0xFFFFFFFFU;
  199.     huffTable[i + 32] = 0x80000000U;
  200.   }
  201.   unsigned int  n = 0;
  202.   unsigned char prvLen = 1;
  203.   for (size_t i = 0; i < symCnt; i++)
  204.   {
  205.     unsigned char len = (unsigned char) (huffTable[i + 64] >> 24);
  206.     huffTable[i + 64] = huffTable[i + 64] & 0x00FFFFFFU;
  207.     if (len != prvLen || i == 0)
  208.     {
  209.       for ( ; prvLen < len; prvLen++)
  210.       {
  211.         huffTable[prvLen - 1] = n;
  212.         n = n << 1;
  213.       }
  214.       huffTable[len + 31] = (unsigned int) (i + 64) - n;
  215.     }
  216.     n++;
  217.     if ((i + 1) >= symCnt)
  218.       huffTable[len - 1] = n;
  219.   }
  220. }
  221.  
  222. // huffTable[N] = limit (last valid code + 1) for code length N+1
  223. // huffTable[N+32] = base index in huffTable for code length N+1
  224.  
  225. unsigned int ZLibDecompressor::huffmanDecode(
  226.     const std::vector< unsigned int >& huffTable)
  227. {
  228.   const unsigned int  *t = &(huffTable.front());
  229.   if (!srBitCnt)
  230.   {
  231.     sr = readU16LE();
  232.     srBitCnt = 16;
  233.   }
  234.   unsigned int  b = sr & 1U;
  235.   sr = sr >> 1;
  236.   srBitCnt--;
  237.   if (b >= *t)
  238.   {
  239.     do
  240.     {
  241.       if (!srBitCnt)
  242.       {
  243.         sr = readU16LE();
  244.         srBitCnt = 16;
  245.         do
  246.         {
  247.           t++;
  248.           b = (b << 1) | (sr & 1U);
  249.           sr = sr >> 1;
  250.           srBitCnt--;
  251.         }
  252.         while (b >= *t);
  253.         break;
  254.       }
  255.       t++;
  256.       b = (b << 1) | (sr & 1U);
  257.       sr = sr >> 1;
  258.       srBitCnt--;
  259.     }
  260.     while (b >= *t);
  261.   }
  262.   b = b + t[32];
  263.   if (b >= huffTable.size())
  264.   {
  265.     throw std::runtime_error(std::string("invalid Huffman code "
  266.                                          "in ZLib compressed data"));
  267.   }
  268.   return huffTable[b];
  269. }
  270.  
  271. ZLibDecompressor::ZLibDecompressor()
  272.   : bufPos(0),
  273.     bufEnd(0),
  274.     inPtr((unsigned char *) 0),
  275.     inBufEnd((unsigned char *) 0),
  276.     sr(0x0000),
  277.     srBitCnt(0)
  278. {
  279. }
  280.  
  281. ZLibDecompressor::~ZLibDecompressor()
  282. {
  283. }
  284.  
  285. size_t ZLibDecompressor::decompressData(const unsigned char *inBuf,
  286.                                         size_t compressedSize,
  287.                                         size_t uncompressedSize)
  288. {
  289.   bufPos = 0;
  290.   bufEnd = 0;
  291.   inPtr = inBuf;
  292.   inBufEnd = inBuf + compressedSize;
  293.   sr = 0x0000;
  294.   srBitCnt = 0;
  295.   buf.resize(uncompressedSize);
  296.  
  297.   {
  298.     // CMF, FLG
  299.     unsigned short  h = readU16BE();
  300.     if ((h & 0x8F20) != 0x0800 || (h % 31) != 0)
  301.     {
  302.       throw std::runtime_error(std::string("invalid or unsupported "
  303.                                            "ZLib compression method"));
  304.     }
  305.   }
  306.   std::vector< unsigned int >   huffTable1;     // literals and length codes
  307.   std::vector< unsigned int >   huffTable2;     // distance codes
  308.   std::vector< unsigned int >   huffTable3;     // code length codes
  309.   std::vector< unsigned char >  lenTbl;         // tmp table for symbol lengths
  310.   unsigned char *wp = &(buf.front());
  311.   size_t        bytesLeft = uncompressedSize;
  312.   unsigned int  s1 = 1;
  313.   unsigned int  s2 = 0;
  314.   while (bytesLeft)
  315.   {
  316.     // read Deflate block header
  317.     unsigned char bhdr = (unsigned char) readBitsRR(3);
  318.     if (!(bhdr & 6))                    // no compression
  319.     {
  320.       srReset();
  321.       size_t  len = readU16LE();
  322.       if ((len ^ readU16LE()) != 0xFFFF)
  323.       {
  324.         throw std::runtime_error(std::string("invalid or corrupt "
  325.                                              "ZLib compressed data"));
  326.       }
  327.       for ( ; len && bytesLeft; wp++, len--, bytesLeft--)
  328.       {
  329.         *wp = readU8();
  330.         s1 = s1 + *wp;                  // update Adler-32 checksum
  331.         s1 = (s1 < 65521U ? s1 : (s1 - 65521U));
  332.         s2 = s2 + s1;
  333.         s2 = (s2 < 65521U ? s2 : (s2 - 65521U));
  334.       }
  335.     }
  336.     else if ((bhdr & 6) == 6)           // reserved (invalid)
  337.     {
  338.       throw std::runtime_error(std::string("invalid Deflate block type "
  339.                                            "in ZLib compressed data"));
  340.     }
  341.     else                                // compressed block
  342.     {
  343.       if (bhdr & 4)                     // dynamic Huffman code
  344.       {
  345.         size_t  hLit = readBitsRR(5) + 257;
  346.         size_t  hDist = readBitsRR(5) + 1;
  347.         size_t  hCLen = readBitsRR(4) + 4;
  348.         lenTbl.resize(19);
  349.         for (size_t i = 0; i < lenTbl.size(); i++)
  350.           lenTbl[i] = 0;
  351.         for (size_t i = 0; i < hCLen; i++)
  352.         {
  353.           size_t  j =
  354.               (i < 3 ? (i + 16) : ((i & 1) == 0 ?
  355.                                    ((i >> 1) + 6) : (((19 - i) >> 1) & 7)));
  356.           lenTbl[j] = (unsigned char) readBitsRR(3);
  357.         }
  358.         huffmanBuildDecodeTable(huffTable3, lenTbl);
  359.         unsigned char rleCode = 0;
  360.         unsigned char rleLen = 0;
  361.         for (size_t t = 0; t < 2; t++)
  362.         {
  363.           lenTbl.resize(t == 0 ? hLit : hDist);
  364.           for (size_t i = 0; i < lenTbl.size(); i++)
  365.           {
  366.             if (rleLen)
  367.             {
  368.               lenTbl[i] = rleCode;
  369.               rleLen--;
  370.               continue;
  371.             }
  372.             unsigned char c = (unsigned char) huffmanDecode(huffTable3);
  373.             if (c < 16)
  374.             {
  375.               lenTbl[i] = c;
  376.               rleCode = c;
  377.             }
  378.             else if (c == 16)
  379.             {
  380.               lenTbl[i] = rleCode;
  381.               rleLen = (unsigned char) readBitsRR(2) + 2;
  382.             }
  383.             else
  384.             {
  385.               lenTbl[i] = 0;
  386.               rleCode = 0;
  387.               if (c == 17)
  388.                 rleLen = (unsigned char) readBitsRR(3) + 2;
  389.               else
  390.                 rleLen = (unsigned char) readBitsRR(7) + 10;
  391.             }
  392.           }
  393.           huffmanBuildDecodeTable((t == 0 ? huffTable1 : huffTable2), lenTbl);
  394.         }
  395.       }
  396.       else                              // fixed Huffman code
  397.       {
  398.         lenTbl.resize(288);
  399.         for (size_t i = 0; i < lenTbl.size(); i++)
  400.           lenTbl[i] = (i < 144 ? 8 : (i < 256 ? 9 : (i < 280 ? 7 : 8)));
  401.         huffmanBuildDecodeTable(huffTable1, lenTbl);
  402.         lenTbl.resize(32);
  403.         for (size_t i = 0; i < lenTbl.size(); i++)
  404.           lenTbl[i] = 5;
  405.         huffmanBuildDecodeTable(huffTable2, lenTbl);
  406.       }
  407.       while (true)
  408.       {
  409.         unsigned int  c = huffmanDecode(huffTable1);
  410.         if (c == 256)
  411.           break;
  412.         if (!bytesLeft)
  413.         {
  414.           throw std::runtime_error(std::string("invalid or corrupt "
  415.                                                "ZLib compressed data"));
  416.         }
  417.         if (c < 256)                    // literal byte
  418.         {
  419.           *wp = (unsigned char) c;
  420.           s1 = s1 + *wp;                // update Adler-32 checksum
  421.           s1 = (s1 < 65521U ? s1 : (s1 - 65521U));
  422.           s2 = s2 + s1;
  423.           s2 = (s2 < 65521U ? s2 : (s2 - 65521U));
  424.           wp++;
  425.           bytesLeft--;
  426.           continue;
  427.         }
  428.         size_t  lzLen = c - 254;
  429.         if (lzLen == 31)
  430.         {
  431.           lzLen = 258;
  432.         }
  433.         else if (lzLen >= 11)
  434.         {
  435.           unsigned char nBits = (unsigned char) ((lzLen - 7) >> 2);
  436.           lzLen = ((((lzLen - 7) & 3) | 4) << nBits) + readBitsRR(nBits) + 3;
  437.         }
  438.         size_t  offs = huffmanDecode(huffTable2);
  439.         if (offs >= 4)
  440.         {
  441.           if (offs >= 30)
  442.           {
  443.             throw std::runtime_error(std::string("invalid or corrupt "
  444.                                                  "ZLib compressed data"));
  445.           }
  446.           unsigned char nBits = (unsigned char) ((offs - 2) >> 1);
  447.           offs = ((((offs - 2) & 1) | 2) << nBits) | readBitsRR(nBits);
  448.         }
  449.         offs++;
  450.         if (offs > size_t(wp - &(buf.front())))
  451.         {
  452.           throw std::runtime_error(std::string("invalid LZ77 offset "
  453.                                                "in ZLib compressed data"));
  454.         }
  455.         const unsigned char *rp = wp - offs;
  456.         // copy LZ77 sequence
  457.         for ( ; lzLen && bytesLeft; rp++, wp++, lzLen--, bytesLeft--)
  458.         {
  459.           *wp = *rp;
  460.           s1 = s1 + *wp;                // update Adler-32 checksum
  461.           s1 = (s1 < 65521U ? s1 : (s1 - 65521U));
  462.           s2 = s2 + s1;
  463.           s2 = (s2 < 65521U ? s2 : (s2 - 65521U));
  464.         }
  465.       }
  466.     }
  467.     if (bhdr & 1)
  468.     {
  469.       // final block
  470.       uncompressedSize = uncompressedSize - bytesLeft;
  471.       break;
  472.     }
  473.   }
  474.   srReset();
  475.   // verify Adler-32 checksum
  476.   if (readU32BE() != ((s2 << 16) | s1))
  477.   {
  478.     throw std::runtime_error(std::string("checksum error "
  479.                                          "in ZLib compressed data"));
  480.   }
  481.  
  482.   bufEnd = uncompressedSize;
  483.   return uncompressedSize;
  484. }
  485.  
  486. class FileBuffer
  487. {
  488.  protected:
  489.   const unsigned char *fileBuf;
  490.   size_t  fileBufSize;
  491.   size_t  filePos;
  492.   std::FILE *fileStream;
  493.   static unsigned int swapUInt32(unsigned int n);
  494.   unsigned char readUInt8();
  495.   unsigned short readUInt16();
  496.   unsigned int readUInt32();
  497.   int readInt32();
  498.   float readFloat();
  499.   unsigned long long readUInt64();
  500.   static inline bool checkType(unsigned int id, const char *s);
  501.   FileBuffer(const unsigned char *fileData, size_t fileSize);
  502.   FileBuffer(const char *fileName);
  503.  public:
  504.   virtual ~FileBuffer();
  505. };
  506.  
  507. unsigned int FileBuffer::swapUInt32(unsigned int n)
  508. {
  509.   n = ((n & 0xFF00FF00U) >> 8) | ((n & 0x00FF00FFU) << 8);
  510.   n = ((n & 0xFFFF0000U) >> 16) | ((n & 0x0000FFFFU) << 16);
  511.   return n;
  512. }
  513.  
  514. unsigned char FileBuffer::readUInt8()
  515. {
  516.   if ((filePos + 1) > fileBufSize)
  517.     throw std::runtime_error(std::string("end of input file"));
  518.   unsigned char tmp = fileBuf[filePos];
  519.   filePos++;
  520.   return tmp;
  521. }
  522.  
  523. unsigned short FileBuffer::readUInt16()
  524. {
  525.   if ((filePos + 2) > fileBufSize)
  526.     throw std::runtime_error(std::string("end of input file"));
  527.   unsigned short  tmp = fileBuf[filePos];
  528.   tmp |= ((unsigned short) fileBuf[filePos + 1] << 8);
  529.   filePos += 2;
  530.   return tmp;
  531. }
  532.  
  533. unsigned int FileBuffer::readUInt32()
  534. {
  535.   if ((filePos + 4) > fileBufSize)
  536.     throw std::runtime_error(std::string("end of input file"));
  537.   unsigned int  tmp = fileBuf[filePos];
  538.   tmp |= ((unsigned int) fileBuf[filePos + 1] << 8);
  539.   tmp |= ((unsigned int) fileBuf[filePos + 2] << 16);
  540.   tmp |= ((unsigned int) fileBuf[filePos + 3] << 24);
  541.   filePos += 4;
  542.   return tmp;
  543. }
  544.  
  545. int FileBuffer::readInt32()
  546. {
  547.   if ((filePos + 4) > fileBufSize)
  548.     throw std::runtime_error(std::string("end of input file"));
  549.   unsigned int  tmp = fileBuf[filePos];
  550.   tmp |= ((unsigned int) fileBuf[filePos + 1] << 8);
  551.   tmp |= ((unsigned int) fileBuf[filePos + 2] << 16);
  552.   tmp |= ((unsigned int) fileBuf[filePos + 3] << 24);
  553.   filePos += 4;
  554.   if (!(tmp & 0x80000000U))
  555.     return int(tmp);
  556.   return (-1 - int(~tmp));
  557. }
  558.  
  559. float FileBuffer::readFloat()
  560. {
  561.   if ((filePos + 4) > fileBufSize)
  562.     throw std::runtime_error(std::string("end of input file"));
  563.   unsigned int  tmp = fileBuf[filePos];
  564.   tmp |= ((unsigned int) fileBuf[filePos + 1] << 8);
  565.   tmp |= ((unsigned int) fileBuf[filePos + 2] << 16);
  566.   tmp |= ((unsigned int) fileBuf[filePos + 3] << 24);
  567.   filePos += 4;
  568.   int     e = int((tmp >> 23) & 0xFFU);
  569.   if (e == 0x00 || e == 0xFF)
  570.     return 0.0f;
  571.   double  m = double(int((tmp & 0x007FFFFFU) | 0x00800000U));
  572.   m = std::ldexp(m, e - 150);
  573.   if (tmp & 0x80000000U)
  574.     m = -m;
  575.   return float(m);
  576. }
  577.  
  578. unsigned long long FileBuffer::readUInt64()
  579. {
  580.   if ((filePos + 8) > fileBufSize)
  581.     throw std::runtime_error(std::string("end of input file"));
  582.   unsigned long long  tmp = fileBuf[filePos];
  583.   tmp |= ((unsigned long long) fileBuf[filePos + 1] << 8);
  584.   tmp |= ((unsigned long long) fileBuf[filePos + 2] << 16);
  585.   tmp |= ((unsigned long long) fileBuf[filePos + 3] << 24);
  586.   tmp |= ((unsigned long long) fileBuf[filePos + 4] << 32);
  587.   tmp |= ((unsigned long long) fileBuf[filePos + 5] << 40);
  588.   tmp |= ((unsigned long long) fileBuf[filePos + 6] << 48);
  589.   tmp |= ((unsigned long long) fileBuf[filePos + 7] << 56);
  590.   filePos += 8;
  591.   return tmp;
  592. }
  593.  
  594. inline bool FileBuffer::checkType(unsigned int id, const char *s)
  595. {
  596.   return (char(id & 0xFF) == s[0] &&
  597.           char((id >> 8) & 0xFF) == s[1] &&
  598.           char((id >> 16) & 0xFF) == s[2] &&
  599.           char((id >> 24) & 0xFF) == s[3]);
  600. }
  601.  
  602. FileBuffer::FileBuffer(const unsigned char *fileData, size_t fileSize)
  603.   : fileBuf(fileData),
  604.     fileBufSize(fileSize),
  605.     filePos(0),
  606.     fileStream((std::FILE *) 0)
  607. {
  608. }
  609.  
  610. FileBuffer::FileBuffer(const char *fileName)
  611.   : filePos(0),
  612.     fileStream((std::FILE *) 0)
  613. {
  614.   if (!fileName || *fileName == '\0')
  615.     throw std::runtime_error(std::string("empty input file name"));
  616.   try
  617.   {
  618.     fileStream = std::fopen(fileName, "rb");
  619.     if (!fileStream)
  620.       throw std::runtime_error(std::string("error loading input file"));
  621.     if (std::fseek(fileStream, 0L, SEEK_END) < 0)
  622.       throw std::runtime_error(std::string("error loading input file"));
  623.     long    fsize = std::ftell(fileStream);
  624.     if (fsize < 0L || std::fseek(fileStream, 0L, SEEK_SET) < 0)
  625.       throw std::runtime_error(std::string("error loading input file"));
  626.     fileBufSize = size_t(fsize);
  627. #if defined(_WIN32) || defined(_WIN64)
  628.     int     fileDesc = _fileno(fileStream);
  629. #else
  630.     int     fileDesc = fileno(fileStream);
  631. #endif
  632.     fileBuf = (unsigned char *) mmap(0, fileBufSize, PROT_READ, MAP_PRIVATE,
  633.                                      fileDesc, 0);
  634.     if ((void *) fileBuf == MAP_FAILED)
  635.       throw std::runtime_error(std::string("error loading input file"));
  636.   }
  637.   catch (...)
  638.   {
  639.     if (fileStream)
  640.       std::fclose(fileStream);
  641.     throw;
  642.   }
  643. }
  644.  
  645. FileBuffer::~FileBuffer()
  646. {
  647.   if (fileStream)
  648.   {
  649.     munmap((void *) fileBuf, fileBufSize);
  650.     std::fclose(fileStream);
  651.   }
  652. }
  653.  
  654. class BTDFile : public FileBuffer
  655. {
  656.  protected:
  657.   ZLibDecompressor  zlibDecompressor;
  658.   size_t  heightMapResX;        // landscape total X resolution (nCellsX * 128)
  659.   size_t  heightMapResY;        // landscape total Y resolution (nCellsY * 128)
  660.   int     cellMinX;             // X coordinate of cell in SW corner
  661.   int     cellMinY;             // Y coordinate of cell in SW corner
  662.   int     cellMaxX;             // X coordinate of cell in NE corner
  663.   int     cellMaxY;             // Y coordinate of cell in NE corner
  664.   size_t  nCellsX;              // world map X size in cells
  665.   size_t  nCellsY;              // world map Y size in cells
  666.   float   worldHeightMin;       // world map minimum height
  667.   float   worldHeightMax;       // world map maximum height
  668.   size_t  cellHeightMinMaxMapOffs;      // minimum, maximum height for each cell
  669.   size_t  ltexCnt;              // number of land textures
  670.   size_t  ltexOffs;             // table of LTEX form IDs
  671.   size_t  ltexMapOffs;          // 8 x (land texture + 1) for each cell quadrant
  672.   size_t  gcvrCnt;              // number of ground covers
  673.   size_t  gcvrOffs;             // table of GCVR form IDs
  674.   size_t  gcvrMapOffs;          // 8 x ground cover for each cell quadrant
  675.   size_t  heightMapLOD4;        // 1/8 cell resolution
  676.   size_t  landTexturesLOD4;     // 1/8 cell resolution
  677.   size_t  normalsLOD4;          // 1/8 cell resolution
  678.   size_t  nCompressedBlocks;    // number of ZLib compressed blocks
  679.   size_t  zlibBlocksTableOffs;  // table of compressed block offsets and sizes
  680.   size_t  zlibBlocksDataOffs;   // ZLib compressed data
  681.   size_t  zlibBlkTableOffsLOD3;
  682.   size_t  zlibBlkTableOffsLOD2;
  683.   size_t  zlibBlkTableOffsLOD1;
  684.   size_t  zlibBlkTableOffsLOD0;
  685.   // current 8x8 group of cells loaded
  686.   int     curTileX;
  687.   int     curTileY;
  688.   // previous 8x8 group of cells (cached)
  689.   int     prvTileX;
  690.   int     prvTileY;
  691.   // 8x8 cells:
  692.   //   curTileData[y * 1024 + x + 0x00000000] = vertex height
  693.   //   curTileData[y * 1024 + x + 0x00100000] = landscape textures
  694.   //   curTileData[y * 1024 + x + 0x00200000] = ground cover
  695.   //   curTileData[y * 1024 + x + 0x00300000] = normals
  696.   unsigned short  *curTileData;
  697.   unsigned short  *prvTileData;
  698.   std::vector< unsigned short > tileBuf;
  699.   // ----------------
  700.   void loadBlock(unsigned short *tileData, size_t n,
  701.                  unsigned char l, unsigned char b);
  702.   void loadTile(int cellX, int cellY);
  703.  public:
  704.   BTDFile(const char *fileName);
  705.   virtual ~BTDFile();
  706.   inline int getCellMinX() const
  707.   {
  708.     return cellMinX;
  709.   }
  710.   inline int getCellMinY() const
  711.   {
  712.     return cellMinY;
  713.   }
  714.   inline int getCellMaxX() const
  715.   {
  716.     return cellMaxX;
  717.   }
  718.   inline int getCellMaxY() const
  719.   {
  720.     return cellMaxY;
  721.   }
  722.   inline float getMinHeight() const
  723.   {
  724.     return worldHeightMin;
  725.   }
  726.   inline float getMaxHeight() const
  727.   {
  728.     return worldHeightMax;
  729.   }
  730.   unsigned int getLandTexture(size_t n);
  731.   unsigned int getGroundCover(size_t n);
  732.   // buf[128 * 128]
  733.   void getCellHeightMap(float *buf, int cellX, int cellY);
  734.   // buf[128 * 128 * 16], for each vertex, the data format is:
  735.   //   base texture, (additional texture, opacity) * 5, reserved * 5
  736.   //   texture = 0xFF or opacity = 0: no texture
  737.   void getCellLandTexture(unsigned char *buf, int cellX, int cellY);
  738.   // buf[128 * 128 * 8], 0xFF = no ground cover
  739.   void getCellGroundCover(unsigned char *buf, int cellX, int cellY);
  740.   // buf[128 * 128], packed 16-bit format
  741.   void getCellNormals(unsigned short *buf, int cellX, int cellY);
  742. };
  743.  
  744. void BTDFile::loadBlock(unsigned short *tileData, size_t n,
  745.                         unsigned char l, unsigned char b)
  746. {
  747.   if (l >= 2)
  748.     n = (n << 1) + b;
  749.   else if (l == 0 && b != 0)
  750.     n = n + (nCellsY * nCellsX);
  751.   if (l == 3)
  752.     filePos = zlibBlkTableOffsLOD3 + (n << 3);
  753.   else if (l == 2)
  754.     filePos = zlibBlkTableOffsLOD2 + (n << 3);
  755.   else if (l == 1)
  756.     filePos = zlibBlkTableOffsLOD1 + (n << 3);
  757.   else
  758.     filePos = zlibBlkTableOffsLOD0 + (n << 3);
  759.   size_t  offs = readUInt32() + zlibBlocksDataOffs;
  760.   size_t  compressedSize = readUInt32();
  761.   filePos = offs;
  762.   if ((filePos + compressedSize) > fileBufSize)
  763.     throw std::runtime_error(std::string("end of input file"));
  764.   if (zlibDecompressor.decompressData(fileBuf + filePos, compressedSize, 65536)
  765.       != ((l == 0 && b != 0) ? 16384 : ((l >= 2 && b != 0) ? 32768 : 49152)))
  766.   {
  767.     throw std::runtime_error(std::string("error in compressed landscape data"));
  768.   }
  769.   for (size_t y = 0; y < 128; y++)
  770.   {
  771.     for (size_t x = 0; x < 128; x++)
  772.     {
  773.       if ((y & 1) == 0 && !(l == 0 && b != 0))
  774.         x++;
  775.       unsigned short  tmp = zlibDecompressor.readByte();
  776.       if (!(l == 0 && b != 0))
  777.         tmp = tmp | ((unsigned short) zlibDecompressor.readByte() << 8);
  778.       unsigned short  *p = tileData + (((y << 10) + x) << l);
  779.       if (b == 0)
  780.         p[0x00000000] = tmp;    // vertex height
  781.       else if (l == 0)
  782.         p[0x00200000] = tmp;    // ground cover
  783.       else
  784.         p[0x00300000] = tmp;    // normals
  785.     }
  786.   }
  787.   if (b != 0)
  788.     return;
  789.   for (size_t y = 0; y < 128; y++)
  790.   {
  791.     for (size_t x = 0; x < 128; x++)
  792.     {
  793.       if (!(y & 1))
  794.         x++;
  795.       unsigned short  tmp = zlibDecompressor.readByte();
  796.       tmp = tmp | ((unsigned short) zlibDecompressor.readByte() << 8);
  797.       unsigned short  *p = tileData + (((y << 10) + x) << l);
  798.       p[0x00100000] = tmp;      // landscape textures
  799.     }
  800.   }
  801. }
  802.  
  803. void BTDFile::loadTile(int cellX, int cellY)
  804. {
  805.   if (cellX >= curTileX && cellX <= (curTileX + 7) &&
  806.       cellY >= curTileY && cellY <= (curTileY + 7))
  807.   {
  808.     return;
  809.   }
  810.   {
  811.     int     tmp = curTileX;
  812.     curTileX = prvTileX;
  813.     prvTileX = tmp;
  814.     tmp = curTileY;
  815.     curTileY = prvTileY;
  816.     prvTileY = tmp;
  817.     unsigned short  *tmp2 = curTileData;
  818.     curTileData = prvTileData;
  819.     prvTileData = tmp2;
  820.   }
  821.   if (cellX >= curTileX && cellX <= (curTileX + 7) &&
  822.       cellY >= curTileY && cellY <= (curTileY + 7))
  823.   {
  824.     return;
  825.   }
  826.   size_t  x = size_t(cellX - cellMinX) & ~7U;
  827.   size_t  y = size_t(cellY - cellMinY) & ~7U;
  828.   curTileX = int(x) + cellMinX;
  829.   curTileY = int(y) + cellMinY;
  830.   // LOD4
  831.   for (size_t yy = 0; yy < 64; yy++)
  832.   {
  833.     if ((curTileY + int(yy >> 3)) > cellMaxY)
  834.       break;
  835.     for (size_t xx = 0; xx < 64; xx++)
  836.     {
  837.       if ((curTileX + int(xx >> 3)) > cellMaxX)
  838.         break;
  839.       filePos = heightMapLOD4
  840.                 + (((((y << 3) + yy) * (nCellsX << 3)) + ((x << 3) + xx)) << 1);
  841.       curTileData[(((yy << 10) + xx) << 4) + 0x00000000] = readUInt16();
  842.       filePos = landTexturesLOD4
  843.                 + (((((y << 3) + yy) * (nCellsX << 3)) + ((x << 3) + xx)) << 1);
  844.       curTileData[(((yy << 10) + xx) << 4) + 0x00100000] = readUInt16();
  845.       filePos = normalsLOD4
  846.                 + (((((y << 3) + yy) * (nCellsX << 3)) + ((x << 3) + xx)) << 1);
  847.       curTileData[(((yy << 10) + xx) << 4) + 0x00300000] = readUInt16();
  848.     }
  849.   }
  850.   // LOD3..LOD0
  851.   for (unsigned char l = 4; l-- > 0; )
  852.   {
  853.     for (size_t yy = 0; yy < size_t(8 >> l); yy++)
  854.     {
  855.       size_t  yc = (y >> l) + yy;
  856.       if (yc >= ((nCellsY + (1 << l) - 1) >> l))
  857.         break;
  858.       for (size_t xx = 0; xx < size_t(8 >> l); xx++)
  859.       {
  860.         size_t  xc = (x >> l) + xx;
  861.         if (xc >= ((nCellsX + (1 << l) - 1) >> l))
  862.           break;
  863.         size_t  n = yc * ((nCellsX + (1 << l) - 1) >> l) + xc;
  864.         unsigned short  *p =
  865.             curTileData + (((yy << l) << 17) + ((xx << l) << 7));
  866.         loadBlock(p, n, l, 0);
  867.         if (l != 1)
  868.           loadBlock(p, n, l, 1);
  869.       }
  870.     }
  871.   }
  872. }
  873.  
  874. BTDFile::BTDFile(const char *fileName)
  875.   : FileBuffer(fileName)
  876. {
  877.   if (!checkType(readUInt32(), "BTDB"))
  878.     throw std::runtime_error(std::string("input file format is not BTD"));
  879.   if (readUInt32() != 6U)
  880.     throw std::runtime_error(std::string("unsupported BTD format version"));
  881.   // TODO: check header data for errors
  882.   worldHeightMin = readFloat();
  883.   worldHeightMax = readFloat();
  884.   heightMapResX = readUInt32();
  885.   heightMapResY = readUInt32();
  886.   cellMinX = readInt32();
  887.   cellMinY = readInt32();
  888.   cellMaxX = readInt32();
  889.   cellMaxY = readInt32();
  890.   nCellsX = size_t(cellMaxX + 1 - cellMinX);
  891.   nCellsY = size_t(cellMaxY + 1 - cellMinY);
  892.   ltexCnt = readUInt32();
  893.   ltexOffs = filePos;
  894.   for (size_t i = 0; i < ltexCnt; i++)
  895.     (void) readUInt32();
  896.   cellHeightMinMaxMapOffs = filePos;
  897.   filePos = filePos + ((nCellsY * nCellsX) << 3);
  898.   ltexMapOffs = filePos;
  899.   filePos = filePos + ((nCellsY * nCellsX) << 5);
  900.   gcvrCnt = readUInt32();
  901.   gcvrOffs = filePos;
  902.   for (size_t i = 0; i < gcvrCnt; i++)
  903.     (void) readUInt32();
  904.   gcvrMapOffs = filePos;
  905.   filePos = filePos + ((nCellsY * nCellsX) << 5);
  906.   heightMapLOD4 = filePos;
  907.   filePos = filePos + ((nCellsY * nCellsX) << 7);
  908.   landTexturesLOD4 = filePos;
  909.   filePos = filePos + ((nCellsY * nCellsX) << 7);
  910.   normalsLOD4 = filePos;
  911.   filePos = filePos + ((nCellsY * nCellsX) << 7);
  912.   zlibBlocksTableOffs = filePos;
  913.   zlibBlkTableOffsLOD3 = filePos;
  914.   filePos = filePos + (((nCellsY + 7) >> 3) * ((nCellsX + 7) >> 3) * 2 * 8);
  915.   zlibBlkTableOffsLOD2 = filePos;
  916.   filePos = filePos + (((nCellsY + 3) >> 2) * ((nCellsX + 3) >> 2) * 2 * 8);
  917.   zlibBlkTableOffsLOD1 = filePos;
  918.   filePos = filePos + (((nCellsY + 1) >> 1) * ((nCellsX + 1) >> 1) * 8);
  919.   zlibBlkTableOffsLOD0 = filePos;
  920.   filePos = filePos + (nCellsY * nCellsX * 2 * 8);
  921.   zlibBlocksDataOffs = filePos;
  922.   nCompressedBlocks = (filePos - zlibBlocksTableOffs) >> 3;
  923.   (void) readUInt8();
  924.   curTileX = 0x7FFFFFF0;
  925.   curTileY = 0x7FFFFFF0;
  926.   prvTileX = 0x7FFFFFF0;
  927.   prvTileY = 0x7FFFFFF0;
  928.   tileBuf.resize(128 * 128 * 4 * 8 * 8 * 2, 0);
  929.   curTileData = &(tileBuf.front());
  930.   prvTileData = curTileData + (128 * 128 * 4 * 8 * 8);
  931. }
  932.  
  933. BTDFile::~BTDFile()
  934. {
  935. }
  936.  
  937. unsigned int BTDFile::getLandTexture(size_t n)
  938. {
  939.   if (n >= ltexCnt)
  940.     return 0U;
  941.   filePos = ltexOffs + (n << 2);
  942.   return readUInt32();
  943. }
  944.  
  945. unsigned int BTDFile::getGroundCover(size_t n)
  946. {
  947.   if (n >= gcvrCnt)
  948.     return 0U;
  949.   filePos = gcvrOffs + (n << 2);
  950.   return readUInt32();
  951. }
  952.  
  953. void BTDFile::getCellHeightMap(float *buf, int cellX, int cellY)
  954. {
  955.   loadTile(cellX, cellY);
  956.   size_t  x0 = size_t((cellX - cellMinX) & 7) << 7;
  957.   size_t  y0 = size_t((cellY - cellMinY) & 7) << 7;
  958.   for (size_t yc = 0; yc < 128; yc++)
  959.   {
  960.     for (size_t xc = 0; xc < 128; xc++)
  961.     {
  962.       int     tmp = int(curTileData[((y0 + yc) << 10) + x0 + xc]);
  963.       float   z = float(tmp) * float(1.0 / 65535.0);
  964.       z = z * (worldHeightMax - worldHeightMin) + worldHeightMin;
  965.       buf[(yc << 7) + xc] = z;
  966.     }
  967.   }
  968. }
  969.  
  970. void BTDFile::getCellLandTexture(unsigned char *buf, int cellX, int cellY)
  971. {
  972.   loadTile(cellX, cellY);
  973.   size_t  x = size_t(cellX - cellMinX);
  974.   size_t  y = size_t(cellY - cellMinY);
  975.   size_t  x0 = (x & 7) << 7;
  976.   size_t  y0 = (y & 7) << 7;
  977.   unsigned char l[8];
  978.   for (size_t i = 0; i < 8; i++)
  979.     l[i] = 0xFF;
  980.   for (size_t q = 0; q < 4; q++)
  981.   {
  982.     unsigned char defaultTexture = 0xFF;
  983.     size_t  offs =
  984.         ((y << 1) | (q >> 1)) * (nCellsX << 1) + ((x << 1) | (q & 1));
  985.     filePos = (offs << 3) + ltexMapOffs;
  986.     for (size_t i = 0; i < 8; i++)
  987.     {
  988.       unsigned char tmp = readUInt8();
  989.       if (tmp == 0 || tmp > ltexCnt)
  990.         tmp = 0xFF;
  991.       else
  992.         tmp = (unsigned char) (ltexCnt - tmp);
  993.       l[i] = tmp;
  994.       if (tmp != 0xFF)
  995.         defaultTexture = tmp;
  996.     }
  997.     for (size_t yy = 0; yy < 64; yy++)
  998.     {
  999.       for (size_t xx = 0; xx < 64; xx++)
  1000.       {
  1001.         size_t  xc = ((q & 1) << 6) | xx;
  1002.         size_t  yc = ((q & 2) << 5) | yy;
  1003.         unsigned char *bufp = buf + (((yc << 7) | xc) << 4);
  1004.         bufp[0] = defaultTexture;
  1005.         for (size_t i = 1; i < 16; i++)
  1006.           bufp[i] = ((i < 11 && (i & 1) != 0) ? 0xFF : 0x00);
  1007.         unsigned int  tmp =
  1008.             curTileData[((y0 + yc) << 10) + x0 + xc + 0x00100000];
  1009.         for (int i = 4; i >= 0; i--)
  1010.         {
  1011.           if ((tmp & 0x7000) != 0U && l[i] != 0xFF)
  1012.           {
  1013.             bufp[1] = l[i];
  1014.             bufp[2] = (unsigned char) ((((tmp >> 12) & 7) * 73) >> 1);
  1015.             bufp = bufp + 2;
  1016.           }
  1017.           tmp = tmp << 3;
  1018.         }
  1019.       }
  1020.     }
  1021.   }
  1022. }
  1023.  
  1024. void BTDFile::getCellGroundCover(unsigned char *buf, int cellX, int cellY)
  1025. {
  1026.   loadTile(cellX, cellY);
  1027.   size_t  x = size_t(cellX - cellMinX);
  1028.   size_t  y = size_t(cellY - cellMinY);
  1029.   size_t  x0 = (x & 7) << 7;
  1030.   size_t  y0 = (y & 7) << 7;
  1031.   unsigned char g[8];
  1032.   for (size_t i = 0; i < 8; i++)
  1033.     g[i] = 0xFF;
  1034.   for (size_t q = 0; q < 4; q++)
  1035.   {
  1036.     size_t  offs =
  1037.         ((y << 1) | (q >> 1)) * (nCellsX << 1) + ((x << 1) | (q & 1));
  1038.     filePos = (offs << 3) + gcvrMapOffs;
  1039.     for (size_t i = 0; i < 8; i++)
  1040.     {
  1041.       unsigned char tmp = readUInt8();
  1042.       if (tmp >= gcvrCnt)
  1043.         tmp = 0xFF;
  1044.       g[i] = tmp;
  1045.     }
  1046.     for (size_t yy = 0; yy < 64; yy++)
  1047.     {
  1048.       for (size_t xx = 0; xx < 64; xx++)
  1049.       {
  1050.         size_t  xc = ((q & 1) << 6) | xx;
  1051.         size_t  yc = ((q & 2) << 5) | yy;
  1052.         unsigned char *bufp = buf + (((yc << 7) | xc) << 3);
  1053.         unsigned int  tmp =
  1054.             curTileData[((y0 + yc) << 10) + x0 + xc + 0x00200000];
  1055.         for (int i = 0; i < 8; i++)
  1056.           bufp[i] = 0xFF;
  1057.         for (int i = 7; i >= 0; i--)
  1058.         {
  1059.           if ((tmp & (1U << i)) != 0U && g[i] != 0xFF)
  1060.             *(bufp++) = g[i];
  1061.         }
  1062.       }
  1063.     }
  1064.   }
  1065. }
  1066.  
  1067. void BTDFile::getCellNormals(unsigned short *buf, int cellX, int cellY)
  1068. {
  1069.   loadTile(cellX, cellY);
  1070.   size_t  x = size_t(cellX - cellMinX);
  1071.   size_t  y = size_t(cellY - cellMinY);
  1072.   size_t  x0 = (x & 7) << 7;
  1073.   size_t  y0 = (y & 7) << 7;
  1074.   for (size_t yc = 0; yc < 128; yc = yc + 4)
  1075.   {
  1076.     for (size_t xc = 0; xc < 128; xc = xc + 4)
  1077.     {
  1078.       unsigned short  *bufp = buf + ((yc << 7) | xc);
  1079.       unsigned short  tmp =
  1080.           curTileData[((y0 + yc) << 10) + x0 + xc + 0x00300000];
  1081.       for (int i = 0; i < 16; i++)
  1082.         bufp[((i >> 2) << 7) | (i & 3)] = tmp;
  1083.     }
  1084.   }
  1085. }
  1086.  
  1087. static inline unsigned char blendDithered(unsigned char a, unsigned char b,
  1088.                                           unsigned char opacityB, int x, int y)
  1089. {
  1090.   static const unsigned char  t[64] =
  1091.   {
  1092.      0, 48, 12, 60,  3, 51, 15, 63, 32, 16, 44, 28, 35, 19, 47, 31,
  1093.      8, 56,  4, 52, 11, 59,  7, 55, 40, 24, 36, 20, 43, 27, 39, 23,
  1094.      2, 50, 14, 62,  1, 49, 13, 61, 34, 18, 46, 30, 33, 17, 45, 29,
  1095.     10, 58,  6, 54,  9, 57,  5, 53, 42, 26, 38, 22, 41, 25, 37, 21
  1096.   };
  1097.   unsigned char d = t[((y & 7) << 3) | (x & 7)];
  1098.   return (((((unsigned int) opacityB + 2) >> 2) + d) < 64 ? a : b);
  1099. }
  1100.  
  1101. int main(int argc, char **argv)
  1102. {
  1103.   if (argc != 8 && argc != 9)
  1104.   {
  1105.     std::fprintf(stderr, "Usage: btddump INFILE.BTD OUTFILE FMT "
  1106.                          "XMIN YMIN XMAX YMAX [LOD]\n");
  1107.     std::fprintf(stderr, "    FMT = 0: raw 16-bit height map\n");
  1108.     std::fprintf(stderr, "    FMT = 1: dithered 8-bit height map\n");
  1109.     std::fprintf(stderr, "    FMT = 2: raw landscape textures "
  1110.                          "(8 bytes / vertex)\n");
  1111.     std::fprintf(stderr, "    FMT = 3: dithered 8-bit landscape texture\n");
  1112.     std::fprintf(stderr, "    FMT = 4: raw ground cover (8 bytes / vertex)\n");
  1113.     std::fprintf(stderr, "    FMT = 5: dithered 8-bit ground cover\n");
  1114.     std::fprintf(stderr, "    FMT = 6: raw 16-bit normals\n");
  1115.     std::fprintf(stderr, "    FMT = 7: normals in 24-bit RGB format\n");
  1116.     return 1;
  1117.   }
  1118.   std::FILE *outFile = (std::FILE *) 0;
  1119.   try
  1120.   {
  1121.     BTDFile btdFile(argv[1]);
  1122.     int     outFmt = std::atoi(argv[3]);
  1123.     if (outFmt < 0 || outFmt > 7)
  1124.       throw std::runtime_error(std::string("invalid output format"));
  1125.     int     xMin = std::atoi(argv[4]);
  1126.     int     yMin = std::atoi(argv[5]);
  1127.     int     xMax = std::atoi(argv[6]);
  1128.     int     yMax = std::atoi(argv[7]);
  1129.     if (xMin < btdFile.getCellMinX() || xMax > btdFile.getCellMaxX() ||
  1130.         xMin > xMax)
  1131.     {
  1132.       throw std::runtime_error(std::string("invalid X range"));
  1133.     }
  1134.     if (yMin < btdFile.getCellMinY() || yMax > btdFile.getCellMaxY() ||
  1135.         yMin > yMax)
  1136.     {
  1137.       throw std::runtime_error(std::string("invalid Y range"));
  1138.     }
  1139.     if (outFmt == 0 || outFmt == 1)
  1140.     {
  1141.       std::printf("Minimum height = %f, maximum height = %f\n",
  1142.                   btdFile.getMinHeight(), btdFile.getMaxHeight());
  1143.     }
  1144.     if (outFmt == 2 || outFmt == 3)
  1145.     {
  1146.       for (size_t i = 0; true; i++)
  1147.       {
  1148.         unsigned int  n = btdFile.getLandTexture(i);
  1149.         if (!n)
  1150.           break;
  1151.         std::printf("Land texture %d: 0x%08X\n", int(i), n);
  1152.       }
  1153.     }
  1154.     if (outFmt == 4 || outFmt == 5)
  1155.     {
  1156.       for (size_t i = 0; true; i++)
  1157.       {
  1158.         unsigned int  n = btdFile.getGroundCover(i);
  1159.         if (!n)
  1160.           break;
  1161.         std::printf("Ground cover %d: 0x%08X\n", int(i), n);
  1162.       }
  1163.     }
  1164.     int     l = (outFmt < 6 ? 0 : 2);
  1165.     if (argc > 8)
  1166.     {
  1167.       l = std::atoi(argv[8]);
  1168.       if (l < (outFmt < 6 ? 0 : 2) || l > 4)
  1169.         throw std::runtime_error(std::string("invalid level of detail"));
  1170.     }
  1171. #if defined(_WIN32) || defined(_WIN64)
  1172.     outFile = fopen64(argv[2], "wb");
  1173. #else
  1174.     outFile = std::fopen(argv[2], "wb");
  1175. #endif
  1176.     if (!outFile)
  1177.       throw std::runtime_error(std::string("error opening output file"));
  1178.     std::vector< unsigned char >  outBuf;
  1179.     std::vector< float >          heightBuf(16384, 0.0f);
  1180.     std::vector< unsigned short > normalsBuf(0x00020000, 0);
  1181.     unsigned char *ltexBuf =
  1182.         reinterpret_cast< unsigned char * >(&(normalsBuf.front()));
  1183.     unsigned char *gcvrBuf = ltexBuf;
  1184.     int     x0 = xMin;
  1185.     int     y0 = yMax;
  1186.     int     x = xMin;
  1187.     int     y = yMax;
  1188.     while (true)
  1189.     {
  1190.       static const size_t outFmtDataSizes[8] = { 2, 1, 8, 1, 8, 1, 2, 3 };
  1191.       size_t  w = size_t(xMax + 1 - xMin);
  1192.       if (!outBuf.size())
  1193.       {
  1194.         size_t  h = size_t(((y0 - btdFile.getCellMinY()) & 7) + 1);
  1195.         if (h > size_t(y0 + 1 - yMin))
  1196.           h = size_t(y0 + 1 - yMin);
  1197.         outBuf.resize(w * h * (outFmtDataSizes[outFmt] << (14 - (l << 1))), 0);
  1198.       }
  1199.       switch (outFmt >> 1)
  1200.       {
  1201.         case 0:
  1202.           btdFile.getCellHeightMap(&(heightBuf.front()), x, y);
  1203.           break;
  1204.         case 1:
  1205.           btdFile.getCellLandTexture(ltexBuf, x, y);
  1206.           break;
  1207.         case 2:
  1208.           btdFile.getCellGroundCover(gcvrBuf, x, y);
  1209.           break;
  1210.         case 3:
  1211.           btdFile.getCellNormals(&(normalsBuf.front()), x, y);
  1212.           break;
  1213.       }
  1214.       for (size_t yy = 0; yy < 128; yy = yy + size_t(1 << l))
  1215.       {
  1216.         size_t  offs = (size_t((y0 - y) << 7) | (127 - yy)) >> l;
  1217.         offs = offs * (w << (7 - l)) + (size_t((x - xMin) << 7) >> l);
  1218.         unsigned char *p = &(outBuf.front()) + (offs * outFmtDataSizes[outFmt]);
  1219.         for (size_t xx = 0; xx < 128; xx = xx + size_t(1 << l))
  1220.         {
  1221.           unsigned int  tmp = 0U;
  1222.           switch (outFmt)
  1223.           {
  1224.             case 0:             // raw height map
  1225.             case 1:             // dithered 8-bit height map
  1226.               {
  1227.                 float   z = heightBuf[(yy << 7) | xx];
  1228.                 z = (z - btdFile.getMinHeight())
  1229.                     / (btdFile.getMaxHeight() - btdFile.getMinHeight());
  1230.                 z = (z > 0.0f ? (z < 1.0f ? z : 1.0f) : 0.0f);
  1231.                 tmp = (unsigned int) (int(z * 65535.0f + 0.5f));
  1232.               }
  1233.               if (outFmt == 0)
  1234.               {
  1235.                 p[0] = (unsigned char) (tmp & 0xFF);
  1236.                 p[1] = (unsigned char) (tmp >> 8);
  1237.               }
  1238.               else
  1239.               {
  1240.                 tmp = (tmp * 0xFF01U) >> 16;
  1241.                 tmp = blendDithered((unsigned char) (tmp >> 8),
  1242.                                     (unsigned char) ((tmp + 255) >> 8),
  1243.                                     (unsigned char) (tmp & 0xFF),
  1244.                                     int(xx >> l), int((127 - yy) >> l));
  1245.                 p[0] = (unsigned char) tmp;
  1246.               }
  1247.               break;
  1248.             case 2:             // raw land textures
  1249.               p[0] = ltexBuf[((yy << 7) | xx) << 4];
  1250.               for (size_t i = 0; i < 5; i++)
  1251.               {
  1252.                 const unsigned char *ltexPtr =
  1253.                     ltexBuf + ((((yy << 7) | xx) << 4) + (i << 1));
  1254.                 p[i + 1] = ltexPtr[1];
  1255.                 tmp = (tmp >> 3) | ((unsigned int) (ltexPtr[2] & 0xE0) << 7);
  1256.               }
  1257.               p[6] = (unsigned char) (tmp & 0xFF);
  1258.               p[7] = (unsigned char) (tmp >> 8);
  1259.               break;
  1260.             case 3:             // dithered 8-bit land texture
  1261.               tmp = ltexBuf[((yy << 7) | xx) << 4];
  1262.               for (size_t i = 0; i < 5; i++)
  1263.               {
  1264.                 const unsigned char *ltexPtr =
  1265.                     ltexBuf + ((((yy << 7) | xx) << 4) + (i << 1));
  1266.                 tmp = blendDithered((unsigned char) tmp, ltexPtr[1], ltexPtr[2],
  1267.                                     int(xx >> l), int((127 - yy) >> l));
  1268.               }
  1269.               p[0] = (unsigned char) tmp;
  1270.               break;
  1271.             case 4:             // raw ground cover
  1272.               for (size_t i = 0; i < 8; i++)
  1273.                 p[i] = gcvrBuf[(((yy << 7) | xx) << 3) + i];
  1274.               break;
  1275.             case 5:             // dithered 8-bit ground cover
  1276.               tmp = 0xFF;
  1277.               {
  1278.                 static const unsigned char  ditherWeights[16] =
  1279.                 {
  1280.                   1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 8, 8
  1281.                 };
  1282.                 size_t  n = 0;
  1283.                 while (n < 8 && gcvrBuf[(((yy << 7) | xx) << 3) + n] != 0xFF)
  1284.                   n++;
  1285.                 unsigned char d = 0xFF;
  1286.                 for (size_t i = n; i-- > 0; )
  1287.                 {
  1288.                   unsigned char g = gcvrBuf[(((yy << 7) | xx) << 3) + i];
  1289.                   if (tmp == 0xFF)
  1290.                   {
  1291.                     tmp = g;
  1292.                     continue;
  1293.                   }
  1294.                   d = d - (ditherWeights[i + 17 - (n << 1)] << 5);
  1295.                   tmp = blendDithered((unsigned char) tmp, g, d,
  1296.                                       int(xx >> l), int((127 - yy) >> l));
  1297.                 }
  1298.               }
  1299.               p[0] = (unsigned char) tmp;
  1300.               break;
  1301.             case 6:             // raw normals
  1302.               tmp = normalsBuf[(yy << 7) | xx];
  1303.               p[0] = (unsigned char) (tmp & 0xFF);
  1304.               p[1] = (unsigned char) (tmp >> 8);
  1305.               break;
  1306.             case 7:             // normals in 24-bit RGB format
  1307.               tmp = normalsBuf[(yy << 7) | xx];
  1308.               p[0] = (unsigned char) ((tmp & 0x001FU) << 3);
  1309.               p[1] = (unsigned char) ((tmp & 0x03E0U) >> 2);
  1310.               p[2] = (unsigned char) ((tmp & 0xFC00U) >> 8);
  1311.               break;
  1312.           }
  1313.           p = p + outFmtDataSizes[outFmt];
  1314.         }
  1315.       }
  1316.       x++;
  1317.       if (x > xMax || ((x - btdFile.getCellMinX()) & 7) == 0)
  1318.       {
  1319.         y--;
  1320.         if (y < yMin || ((y - btdFile.getCellMinY()) & 7) == 7)
  1321.         {
  1322.           if (x > xMax)
  1323.           {
  1324.             if (std::fwrite(&(outBuf.front()),
  1325.                             sizeof(unsigned char), outBuf.size(), outFile)
  1326.                 != outBuf.size() || std::fflush(outFile) != 0)
  1327.             {
  1328.               throw std::runtime_error(std::string(
  1329.                                            "error writing output file"));
  1330.             }
  1331.             outBuf.clear();
  1332.             x = xMin;
  1333.             if (y < yMin)
  1334.               break;
  1335.             y0 = y;
  1336.           }
  1337.           y = y0;
  1338.           x0 = x;
  1339.         }
  1340.         x = x0;
  1341.       }
  1342.     }
  1343.     std::fclose(outFile);
  1344.   }
  1345.   catch (std::exception& e)
  1346.   {
  1347.     if (outFile)
  1348.       std::fclose(outFile);
  1349.     std::fprintf(stderr, "btddump: %s\n", e.what());
  1350.     return 1;
  1351.   }
  1352.   return 0;
  1353. }
  1354.  
  1355.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement