Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Appalachia.btd file format:
- //
- // 0x00000000-0x00000003: "BTDB"
- // 0x00000004-0x00000007: (int32) 6, format version
- // 0x00000008-0x0000000B: (float) -700.0, mimimum height
- // 0x0000000C-0x0000000F: (float) 38209.996, maximum height
- // 0x00000010-0x00000013: (int32) 25728 (201 * 128), total resolution X
- // 0x00000014-0x00000017: (int32) 25728 (201 * 128), total resolution Y
- // 0x00000018-0x0000001B: (int32) -100, minimum cell X (west)
- // 0x0000001C-0x0000001F: (int32) -100, minimum cell Y (south)
- // 0x00000020-0x00000023: (int32) 100, maximum cell X (east)
- // 0x00000024-0x00000027: (int32) 100, maximum cell Y (north)
- // 0x00000028-0x0000002B: (int32) 43, number of land textures (LTEX records)
- // 0x0000002C-0x000000D7: 43 * int32, LTEX form IDs
- // 0x000000D8-0x0004EF5F: 201 * 201 * float[2], min, max height for each cell
- // 0x0004EF60-0x0018A97F: 201 * 2 * 201 * 2 * byte[8], cell quadrant land
- // textures (43 - LTEX_table_index, or zero if none)
- // 0x0018A980-0x0018A983: (int32) 30, number of ground covers (GCVR records)
- // 0x0018A984-0x0018A9FB: 30 * int32, GCVR form IDs
- // 0x0018A9FC-0x002C641B: 201 * 2 * 201 * 2 * byte[8], cell quadrant ground
- // covers (GCVR_table_index, or 0xFF if none)
- // 0x002C641C-0x007B4C9B: 201 * 8 * 201 * 8 * int16, LOD4 height map,
- // 0 to 65535 maps to minimum height to maximum height
- // 0x007B4C9C-0x00CA351B: 201 * 8 * 201 * 8 * int16, LOD4 land textures,
- // bits[N * 3 to N * 3 + 2] = opacity of texture N,
- // texture 6 is the base texture
- // 0x00CA351C-0x01191D9B: 201 * 8 * 201 * 8 * int16, LOD4 normals (?),
- // Z6Y5X5 format (not sure)
- // 0x01191D9C-0x01250643: 97557 * (int32, int32), pairs of zlib compressed data
- // offset (relative to 0x01250644) and size
- // 0x01250644-EOF: zlib compressed data blocks
- // zlib compressed blocks 0 to 1351 (26 * 26 * 2): LOD3, 8x8 cell groups
- // 1352 to 6553 (51 * 51 * 2): LOD2, 4x4 cell groups
- // 6554 to 16754 (101 * 101): LOD1, 2x2 cell groups
- // 16755 to 57155 (201 * 201): LOD0 height map, LTEX
- // 57156 to 97556 (201 * 201): LOD0 ground cover mask
- // LOD3, LOD2: pairs of height map, LTEX and normals blocks
- // LOD1: height map, land textures block only
- // height map, LTEX block format:
- // 0x0000-0x5FFF: 64 * (64, 128) int16, height map, only the samples
- // not present at lower levels of detail
- // 0x6000-0xBFFF: 64 * (64, 128) int16, land texture opacities
- // normals block format (LOD3 and LOD2 only):
- // 0x0000-0x5FFF: 64 * (64, 128) int16
- // 0x6000-0x7FFF: unused
- // ground cover block format (LOD0 only):
- // 0x0000-0x3FFF: 128 * 128 bytes, bit N is set if ground cover N is enabled
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <cmath>
- #include <string>
- #include <vector>
- #include <set>
- #include <map>
- #include <algorithm>
- #include <exception>
- #include <stdexcept>
- #if defined(_WIN32) || defined(_WIN64)
- extern "C"
- {
- // mman-win32 is required on Windows (https://github.com/alitrack/mman-win32)
- # include "mman.c"
- }
- #else
- # include <sys/mman.h>
- #endif
- class ZLibDecompressor
- {
- protected:
- std::vector< unsigned char > buf;
- size_t bufPos;
- size_t bufEnd;
- const unsigned char *inPtr;
- const unsigned char *inBufEnd;
- unsigned int sr;
- unsigned int srBitCnt;
- inline unsigned char readU8()
- {
- if (inPtr >= inBufEnd)
- throw std::runtime_error(std::string("end of ZLib compressed data"));
- unsigned char c = *(inPtr++);
- return c;
- }
- inline unsigned short readU16LE()
- {
- if ((inPtr + 1) >= inBufEnd)
- throw std::runtime_error(std::string("end of ZLib compressed data"));
- unsigned short w = *(inPtr++);
- w = w | ((unsigned short) *(inPtr++) << 8);
- return w;
- }
- unsigned short readU16BE();
- unsigned int readU32BE();
- inline void srReset()
- {
- if (srBitCnt >= 8U)
- inPtr--;
- sr = 0x0000;
- srBitCnt = 0;
- }
- // read bits packed in Deflate order (LSB first - LSB first)
- // nBits must be in the range 1 to 16
- unsigned int readBitsRR(unsigned char nBits);
- // lenTbl[c] = length of symbol 'c' (0: not used)
- static void huffmanBuildDecodeTable(
- std::vector< unsigned int >& huffTable,
- const std::vector< unsigned char >& lenTbl);
- unsigned int huffmanDecode(const std::vector< unsigned int >& huffTable);
- public:
- ZLibDecompressor();
- virtual ~ZLibDecompressor();
- size_t decompressData(const unsigned char *inBuf,
- size_t compressedSize, size_t uncompressedSize);
- inline size_t dataRemaining() const
- {
- return (bufEnd - bufPos);
- }
- inline unsigned char readByte()
- {
- unsigned char tmp = buf[bufPos];
- bufPos++;
- return tmp;
- }
- const unsigned char& operator[](size_t i) const
- {
- return *(&(buf.front()) + i);
- }
- void clear()
- {
- bufPos = 0;
- bufEnd = 0;
- }
- };
- unsigned short ZLibDecompressor::readU16BE()
- {
- unsigned short w = readU8();
- w = (w << 8) | readU8();
- return w;
- }
- unsigned int ZLibDecompressor::readU32BE()
- {
- unsigned int w = readU16BE();
- w = (w << 16) | readU16BE();
- return w;
- }
- unsigned int ZLibDecompressor::readBitsRR(unsigned char nBits)
- {
- unsigned int w = 0;
- unsigned char b = 0;
- if (!srBitCnt)
- {
- sr = readU16LE();
- srBitCnt = 16;
- }
- if (nBits > srBitCnt)
- {
- w = sr;
- b = (unsigned char) srBitCnt;
- nBits = nBits - (unsigned char) srBitCnt;
- sr = readU16LE();
- srBitCnt = 16;
- }
- w = w | ((sr & ((1U << nBits) - 1U)) << b);
- sr = sr >> nBits;
- srBitCnt = srBitCnt - nBits;
- return w;
- }
- void ZLibDecompressor::huffmanBuildDecodeTable(
- std::vector< unsigned int >& huffTable,
- const std::vector< unsigned char >& lenTbl)
- {
- size_t symCnt = 0;
- for (size_t i = 0; i < lenTbl.size(); i++)
- symCnt += size_t(bool(lenTbl[i]));
- huffTable.resize(symCnt + 64);
- symCnt = 0;
- for (size_t i = 0; i < lenTbl.size(); i++)
- {
- if (lenTbl[i])
- {
- huffTable[symCnt + 64] =
- (unsigned int) i | ((unsigned int) lenTbl[i] << 24);
- symCnt++;
- }
- }
- std::sort(huffTable.begin() + 64, huffTable.end());
- for (size_t i = 0; i < 32; i++)
- {
- huffTable[i] = 0xFFFFFFFFU;
- huffTable[i + 32] = 0x80000000U;
- }
- unsigned int n = 0;
- unsigned char prvLen = 1;
- for (size_t i = 0; i < symCnt; i++)
- {
- unsigned char len = (unsigned char) (huffTable[i + 64] >> 24);
- huffTable[i + 64] = huffTable[i + 64] & 0x00FFFFFFU;
- if (len != prvLen || i == 0)
- {
- for ( ; prvLen < len; prvLen++)
- {
- huffTable[prvLen - 1] = n;
- n = n << 1;
- }
- huffTable[len + 31] = (unsigned int) (i + 64) - n;
- }
- n++;
- if ((i + 1) >= symCnt)
- huffTable[len - 1] = n;
- }
- }
- // huffTable[N] = limit (last valid code + 1) for code length N+1
- // huffTable[N+32] = base index in huffTable for code length N+1
- unsigned int ZLibDecompressor::huffmanDecode(
- const std::vector< unsigned int >& huffTable)
- {
- const unsigned int *t = &(huffTable.front());
- if (!srBitCnt)
- {
- sr = readU16LE();
- srBitCnt = 16;
- }
- unsigned int b = sr & 1U;
- sr = sr >> 1;
- srBitCnt--;
- if (b >= *t)
- {
- do
- {
- if (!srBitCnt)
- {
- sr = readU16LE();
- srBitCnt = 16;
- do
- {
- t++;
- b = (b << 1) | (sr & 1U);
- sr = sr >> 1;
- srBitCnt--;
- }
- while (b >= *t);
- break;
- }
- t++;
- b = (b << 1) | (sr & 1U);
- sr = sr >> 1;
- srBitCnt--;
- }
- while (b >= *t);
- }
- b = b + t[32];
- if (b >= huffTable.size())
- {
- throw std::runtime_error(std::string("invalid Huffman code "
- "in ZLib compressed data"));
- }
- return huffTable[b];
- }
- ZLibDecompressor::ZLibDecompressor()
- : bufPos(0),
- bufEnd(0),
- inPtr((unsigned char *) 0),
- inBufEnd((unsigned char *) 0),
- sr(0x0000),
- srBitCnt(0)
- {
- }
- ZLibDecompressor::~ZLibDecompressor()
- {
- }
- size_t ZLibDecompressor::decompressData(const unsigned char *inBuf,
- size_t compressedSize,
- size_t uncompressedSize)
- {
- bufPos = 0;
- bufEnd = 0;
- inPtr = inBuf;
- inBufEnd = inBuf + compressedSize;
- sr = 0x0000;
- srBitCnt = 0;
- buf.resize(uncompressedSize);
- {
- // CMF, FLG
- unsigned short h = readU16BE();
- if ((h & 0x8F20) != 0x0800 || (h % 31) != 0)
- {
- throw std::runtime_error(std::string("invalid or unsupported "
- "ZLib compression method"));
- }
- }
- std::vector< unsigned int > huffTable1; // literals and length codes
- std::vector< unsigned int > huffTable2; // distance codes
- std::vector< unsigned int > huffTable3; // code length codes
- std::vector< unsigned char > lenTbl; // tmp table for symbol lengths
- unsigned char *wp = &(buf.front());
- size_t bytesLeft = uncompressedSize;
- unsigned int s1 = 1;
- unsigned int s2 = 0;
- while (bytesLeft)
- {
- // read Deflate block header
- unsigned char bhdr = (unsigned char) readBitsRR(3);
- if (!(bhdr & 6)) // no compression
- {
- srReset();
- size_t len = readU16LE();
- if ((len ^ readU16LE()) != 0xFFFF)
- {
- throw std::runtime_error(std::string("invalid or corrupt "
- "ZLib compressed data"));
- }
- for ( ; len && bytesLeft; wp++, len--, bytesLeft--)
- {
- *wp = readU8();
- s1 = s1 + *wp; // update Adler-32 checksum
- s1 = (s1 < 65521U ? s1 : (s1 - 65521U));
- s2 = s2 + s1;
- s2 = (s2 < 65521U ? s2 : (s2 - 65521U));
- }
- }
- else if ((bhdr & 6) == 6) // reserved (invalid)
- {
- throw std::runtime_error(std::string("invalid Deflate block type "
- "in ZLib compressed data"));
- }
- else // compressed block
- {
- if (bhdr & 4) // dynamic Huffman code
- {
- size_t hLit = readBitsRR(5) + 257;
- size_t hDist = readBitsRR(5) + 1;
- size_t hCLen = readBitsRR(4) + 4;
- lenTbl.resize(19);
- for (size_t i = 0; i < lenTbl.size(); i++)
- lenTbl[i] = 0;
- for (size_t i = 0; i < hCLen; i++)
- {
- size_t j =
- (i < 3 ? (i + 16) : ((i & 1) == 0 ?
- ((i >> 1) + 6) : (((19 - i) >> 1) & 7)));
- lenTbl[j] = (unsigned char) readBitsRR(3);
- }
- huffmanBuildDecodeTable(huffTable3, lenTbl);
- unsigned char rleCode = 0;
- unsigned char rleLen = 0;
- for (size_t t = 0; t < 2; t++)
- {
- lenTbl.resize(t == 0 ? hLit : hDist);
- for (size_t i = 0; i < lenTbl.size(); i++)
- {
- if (rleLen)
- {
- lenTbl[i] = rleCode;
- rleLen--;
- continue;
- }
- unsigned char c = (unsigned char) huffmanDecode(huffTable3);
- if (c < 16)
- {
- lenTbl[i] = c;
- rleCode = c;
- }
- else if (c == 16)
- {
- lenTbl[i] = rleCode;
- rleLen = (unsigned char) readBitsRR(2) + 2;
- }
- else
- {
- lenTbl[i] = 0;
- rleCode = 0;
- if (c == 17)
- rleLen = (unsigned char) readBitsRR(3) + 2;
- else
- rleLen = (unsigned char) readBitsRR(7) + 10;
- }
- }
- huffmanBuildDecodeTable((t == 0 ? huffTable1 : huffTable2), lenTbl);
- }
- }
- else // fixed Huffman code
- {
- lenTbl.resize(288);
- for (size_t i = 0; i < lenTbl.size(); i++)
- lenTbl[i] = (i < 144 ? 8 : (i < 256 ? 9 : (i < 280 ? 7 : 8)));
- huffmanBuildDecodeTable(huffTable1, lenTbl);
- lenTbl.resize(32);
- for (size_t i = 0; i < lenTbl.size(); i++)
- lenTbl[i] = 5;
- huffmanBuildDecodeTable(huffTable2, lenTbl);
- }
- while (true)
- {
- unsigned int c = huffmanDecode(huffTable1);
- if (c == 256)
- break;
- if (!bytesLeft)
- {
- throw std::runtime_error(std::string("invalid or corrupt "
- "ZLib compressed data"));
- }
- if (c < 256) // literal byte
- {
- *wp = (unsigned char) c;
- s1 = s1 + *wp; // update Adler-32 checksum
- s1 = (s1 < 65521U ? s1 : (s1 - 65521U));
- s2 = s2 + s1;
- s2 = (s2 < 65521U ? s2 : (s2 - 65521U));
- wp++;
- bytesLeft--;
- continue;
- }
- size_t lzLen = c - 254;
- if (lzLen == 31)
- {
- lzLen = 258;
- }
- else if (lzLen >= 11)
- {
- unsigned char nBits = (unsigned char) ((lzLen - 7) >> 2);
- lzLen = ((((lzLen - 7) & 3) | 4) << nBits) + readBitsRR(nBits) + 3;
- }
- size_t offs = huffmanDecode(huffTable2);
- if (offs >= 4)
- {
- if (offs >= 30)
- {
- throw std::runtime_error(std::string("invalid or corrupt "
- "ZLib compressed data"));
- }
- unsigned char nBits = (unsigned char) ((offs - 2) >> 1);
- offs = ((((offs - 2) & 1) | 2) << nBits) | readBitsRR(nBits);
- }
- offs++;
- if (offs > size_t(wp - &(buf.front())))
- {
- throw std::runtime_error(std::string("invalid LZ77 offset "
- "in ZLib compressed data"));
- }
- const unsigned char *rp = wp - offs;
- // copy LZ77 sequence
- for ( ; lzLen && bytesLeft; rp++, wp++, lzLen--, bytesLeft--)
- {
- *wp = *rp;
- s1 = s1 + *wp; // update Adler-32 checksum
- s1 = (s1 < 65521U ? s1 : (s1 - 65521U));
- s2 = s2 + s1;
- s2 = (s2 < 65521U ? s2 : (s2 - 65521U));
- }
- }
- }
- if (bhdr & 1)
- {
- // final block
- uncompressedSize = uncompressedSize - bytesLeft;
- break;
- }
- }
- srReset();
- // verify Adler-32 checksum
- if (readU32BE() != ((s2 << 16) | s1))
- {
- throw std::runtime_error(std::string("checksum error "
- "in ZLib compressed data"));
- }
- bufEnd = uncompressedSize;
- return uncompressedSize;
- }
- class FileBuffer
- {
- protected:
- const unsigned char *fileBuf;
- size_t fileBufSize;
- size_t filePos;
- std::FILE *fileStream;
- static unsigned int swapUInt32(unsigned int n);
- unsigned char readUInt8();
- unsigned short readUInt16();
- unsigned int readUInt32();
- int readInt32();
- float readFloat();
- unsigned long long readUInt64();
- static inline bool checkType(unsigned int id, const char *s);
- FileBuffer(const unsigned char *fileData, size_t fileSize);
- FileBuffer(const char *fileName);
- public:
- virtual ~FileBuffer();
- };
- unsigned int FileBuffer::swapUInt32(unsigned int n)
- {
- n = ((n & 0xFF00FF00U) >> 8) | ((n & 0x00FF00FFU) << 8);
- n = ((n & 0xFFFF0000U) >> 16) | ((n & 0x0000FFFFU) << 16);
- return n;
- }
- unsigned char FileBuffer::readUInt8()
- {
- if ((filePos + 1) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- unsigned char tmp = fileBuf[filePos];
- filePos++;
- return tmp;
- }
- unsigned short FileBuffer::readUInt16()
- {
- if ((filePos + 2) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- unsigned short tmp = fileBuf[filePos];
- tmp |= ((unsigned short) fileBuf[filePos + 1] << 8);
- filePos += 2;
- return tmp;
- }
- unsigned int FileBuffer::readUInt32()
- {
- if ((filePos + 4) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- unsigned int tmp = fileBuf[filePos];
- tmp |= ((unsigned int) fileBuf[filePos + 1] << 8);
- tmp |= ((unsigned int) fileBuf[filePos + 2] << 16);
- tmp |= ((unsigned int) fileBuf[filePos + 3] << 24);
- filePos += 4;
- return tmp;
- }
- int FileBuffer::readInt32()
- {
- if ((filePos + 4) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- unsigned int tmp = fileBuf[filePos];
- tmp |= ((unsigned int) fileBuf[filePos + 1] << 8);
- tmp |= ((unsigned int) fileBuf[filePos + 2] << 16);
- tmp |= ((unsigned int) fileBuf[filePos + 3] << 24);
- filePos += 4;
- if (!(tmp & 0x80000000U))
- return int(tmp);
- return (-1 - int(~tmp));
- }
- float FileBuffer::readFloat()
- {
- if ((filePos + 4) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- unsigned int tmp = fileBuf[filePos];
- tmp |= ((unsigned int) fileBuf[filePos + 1] << 8);
- tmp |= ((unsigned int) fileBuf[filePos + 2] << 16);
- tmp |= ((unsigned int) fileBuf[filePos + 3] << 24);
- filePos += 4;
- int e = int((tmp >> 23) & 0xFFU);
- if (e == 0x00 || e == 0xFF)
- return 0.0f;
- double m = double(int((tmp & 0x007FFFFFU) | 0x00800000U));
- m = std::ldexp(m, e - 150);
- if (tmp & 0x80000000U)
- m = -m;
- return float(m);
- }
- unsigned long long FileBuffer::readUInt64()
- {
- if ((filePos + 8) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- unsigned long long tmp = fileBuf[filePos];
- tmp |= ((unsigned long long) fileBuf[filePos + 1] << 8);
- tmp |= ((unsigned long long) fileBuf[filePos + 2] << 16);
- tmp |= ((unsigned long long) fileBuf[filePos + 3] << 24);
- tmp |= ((unsigned long long) fileBuf[filePos + 4] << 32);
- tmp |= ((unsigned long long) fileBuf[filePos + 5] << 40);
- tmp |= ((unsigned long long) fileBuf[filePos + 6] << 48);
- tmp |= ((unsigned long long) fileBuf[filePos + 7] << 56);
- filePos += 8;
- return tmp;
- }
- inline bool FileBuffer::checkType(unsigned int id, const char *s)
- {
- return (char(id & 0xFF) == s[0] &&
- char((id >> 8) & 0xFF) == s[1] &&
- char((id >> 16) & 0xFF) == s[2] &&
- char((id >> 24) & 0xFF) == s[3]);
- }
- FileBuffer::FileBuffer(const unsigned char *fileData, size_t fileSize)
- : fileBuf(fileData),
- fileBufSize(fileSize),
- filePos(0),
- fileStream((std::FILE *) 0)
- {
- }
- FileBuffer::FileBuffer(const char *fileName)
- : filePos(0),
- fileStream((std::FILE *) 0)
- {
- if (!fileName || *fileName == '\0')
- throw std::runtime_error(std::string("empty input file name"));
- try
- {
- fileStream = std::fopen(fileName, "rb");
- if (!fileStream)
- throw std::runtime_error(std::string("error loading input file"));
- if (std::fseek(fileStream, 0L, SEEK_END) < 0)
- throw std::runtime_error(std::string("error loading input file"));
- long fsize = std::ftell(fileStream);
- if (fsize < 0L || std::fseek(fileStream, 0L, SEEK_SET) < 0)
- throw std::runtime_error(std::string("error loading input file"));
- fileBufSize = size_t(fsize);
- #if defined(_WIN32) || defined(_WIN64)
- int fileDesc = _fileno(fileStream);
- #else
- int fileDesc = fileno(fileStream);
- #endif
- fileBuf = (unsigned char *) mmap(0, fileBufSize, PROT_READ, MAP_PRIVATE,
- fileDesc, 0);
- if ((void *) fileBuf == MAP_FAILED)
- throw std::runtime_error(std::string("error loading input file"));
- }
- catch (...)
- {
- if (fileStream)
- std::fclose(fileStream);
- throw;
- }
- }
- FileBuffer::~FileBuffer()
- {
- if (fileStream)
- {
- munmap((void *) fileBuf, fileBufSize);
- std::fclose(fileStream);
- }
- }
- class BTDFile : public FileBuffer
- {
- protected:
- ZLibDecompressor zlibDecompressor;
- size_t heightMapResX; // landscape total X resolution (nCellsX * 128)
- size_t heightMapResY; // landscape total Y resolution (nCellsY * 128)
- int cellMinX; // X coordinate of cell in SW corner
- int cellMinY; // Y coordinate of cell in SW corner
- int cellMaxX; // X coordinate of cell in NE corner
- int cellMaxY; // Y coordinate of cell in NE corner
- size_t nCellsX; // world map X size in cells
- size_t nCellsY; // world map Y size in cells
- float worldHeightMin; // world map minimum height
- float worldHeightMax; // world map maximum height
- size_t cellHeightMinMaxMapOffs; // minimum, maximum height for each cell
- size_t ltexCnt; // number of land textures
- size_t ltexOffs; // table of LTEX form IDs
- size_t ltexMapOffs; // 8 x (land texture + 1) for each cell quadrant
- size_t gcvrCnt; // number of ground covers
- size_t gcvrOffs; // table of GCVR form IDs
- size_t gcvrMapOffs; // 8 x ground cover for each cell quadrant
- size_t heightMapLOD4; // 1/8 cell resolution
- size_t landTexturesLOD4; // 1/8 cell resolution
- size_t normalsLOD4; // 1/8 cell resolution
- size_t nCompressedBlocks; // number of ZLib compressed blocks
- size_t zlibBlocksTableOffs; // table of compressed block offsets and sizes
- size_t zlibBlocksDataOffs; // ZLib compressed data
- size_t zlibBlkTableOffsLOD3;
- size_t zlibBlkTableOffsLOD2;
- size_t zlibBlkTableOffsLOD1;
- size_t zlibBlkTableOffsLOD0;
- // current 8x8 group of cells loaded
- int curTileX;
- int curTileY;
- // previous 8x8 group of cells (cached)
- int prvTileX;
- int prvTileY;
- // 8x8 cells:
- // curTileData[y * 1024 + x + 0x00000000] = vertex height
- // curTileData[y * 1024 + x + 0x00100000] = landscape textures
- // curTileData[y * 1024 + x + 0x00200000] = ground cover
- // curTileData[y * 1024 + x + 0x00300000] = normals
- unsigned short *curTileData;
- unsigned short *prvTileData;
- std::vector< unsigned short > tileBuf;
- // ----------------
- void loadBlock(unsigned short *tileData, size_t n,
- unsigned char l, unsigned char b);
- void loadTile(int cellX, int cellY);
- public:
- BTDFile(const char *fileName);
- virtual ~BTDFile();
- inline int getCellMinX() const
- {
- return cellMinX;
- }
- inline int getCellMinY() const
- {
- return cellMinY;
- }
- inline int getCellMaxX() const
- {
- return cellMaxX;
- }
- inline int getCellMaxY() const
- {
- return cellMaxY;
- }
- inline float getMinHeight() const
- {
- return worldHeightMin;
- }
- inline float getMaxHeight() const
- {
- return worldHeightMax;
- }
- unsigned int getLandTexture(size_t n);
- unsigned int getGroundCover(size_t n);
- // buf[128 * 128]
- void getCellHeightMap(float *buf, int cellX, int cellY);
- // buf[128 * 128 * 16], for each vertex, the data format is:
- // base texture, (additional texture, opacity) * 5, reserved * 5
- // texture = 0xFF or opacity = 0: no texture
- void getCellLandTexture(unsigned char *buf, int cellX, int cellY);
- // buf[128 * 128 * 8], 0xFF = no ground cover
- void getCellGroundCover(unsigned char *buf, int cellX, int cellY);
- // buf[128 * 128], packed 16-bit format
- void getCellNormals(unsigned short *buf, int cellX, int cellY);
- };
- void BTDFile::loadBlock(unsigned short *tileData, size_t n,
- unsigned char l, unsigned char b)
- {
- if (l >= 2)
- n = (n << 1) + b;
- else if (l == 0 && b != 0)
- n = n + (nCellsY * nCellsX);
- if (l == 3)
- filePos = zlibBlkTableOffsLOD3 + (n << 3);
- else if (l == 2)
- filePos = zlibBlkTableOffsLOD2 + (n << 3);
- else if (l == 1)
- filePos = zlibBlkTableOffsLOD1 + (n << 3);
- else
- filePos = zlibBlkTableOffsLOD0 + (n << 3);
- size_t offs = readUInt32() + zlibBlocksDataOffs;
- size_t compressedSize = readUInt32();
- filePos = offs;
- if ((filePos + compressedSize) > fileBufSize)
- throw std::runtime_error(std::string("end of input file"));
- if (zlibDecompressor.decompressData(fileBuf + filePos, compressedSize, 65536)
- != ((l == 0 && b != 0) ? 16384 : ((l >= 2 && b != 0) ? 32768 : 49152)))
- {
- throw std::runtime_error(std::string("error in compressed landscape data"));
- }
- for (size_t y = 0; y < 128; y++)
- {
- for (size_t x = 0; x < 128; x++)
- {
- if ((y & 1) == 0 && !(l == 0 && b != 0))
- x++;
- unsigned short tmp = zlibDecompressor.readByte();
- if (!(l == 0 && b != 0))
- tmp = tmp | ((unsigned short) zlibDecompressor.readByte() << 8);
- unsigned short *p = tileData + (((y << 10) + x) << l);
- if (b == 0)
- p[0x00000000] = tmp; // vertex height
- else if (l == 0)
- p[0x00200000] = tmp; // ground cover
- else
- p[0x00300000] = tmp; // normals
- }
- }
- if (b != 0)
- return;
- for (size_t y = 0; y < 128; y++)
- {
- for (size_t x = 0; x < 128; x++)
- {
- if (!(y & 1))
- x++;
- unsigned short tmp = zlibDecompressor.readByte();
- tmp = tmp | ((unsigned short) zlibDecompressor.readByte() << 8);
- unsigned short *p = tileData + (((y << 10) + x) << l);
- p[0x00100000] = tmp; // landscape textures
- }
- }
- }
- void BTDFile::loadTile(int cellX, int cellY)
- {
- if (cellX >= curTileX && cellX <= (curTileX + 7) &&
- cellY >= curTileY && cellY <= (curTileY + 7))
- {
- return;
- }
- {
- int tmp = curTileX;
- curTileX = prvTileX;
- prvTileX = tmp;
- tmp = curTileY;
- curTileY = prvTileY;
- prvTileY = tmp;
- unsigned short *tmp2 = curTileData;
- curTileData = prvTileData;
- prvTileData = tmp2;
- }
- if (cellX >= curTileX && cellX <= (curTileX + 7) &&
- cellY >= curTileY && cellY <= (curTileY + 7))
- {
- return;
- }
- size_t x = size_t(cellX - cellMinX) & ~7U;
- size_t y = size_t(cellY - cellMinY) & ~7U;
- curTileX = int(x) + cellMinX;
- curTileY = int(y) + cellMinY;
- // LOD4
- for (size_t yy = 0; yy < 64; yy++)
- {
- if ((curTileY + int(yy >> 3)) > cellMaxY)
- break;
- for (size_t xx = 0; xx < 64; xx++)
- {
- if ((curTileX + int(xx >> 3)) > cellMaxX)
- break;
- filePos = heightMapLOD4
- + (((((y << 3) + yy) * (nCellsX << 3)) + ((x << 3) + xx)) << 1);
- curTileData[(((yy << 10) + xx) << 4) + 0x00000000] = readUInt16();
- filePos = landTexturesLOD4
- + (((((y << 3) + yy) * (nCellsX << 3)) + ((x << 3) + xx)) << 1);
- curTileData[(((yy << 10) + xx) << 4) + 0x00100000] = readUInt16();
- filePos = normalsLOD4
- + (((((y << 3) + yy) * (nCellsX << 3)) + ((x << 3) + xx)) << 1);
- curTileData[(((yy << 10) + xx) << 4) + 0x00300000] = readUInt16();
- }
- }
- // LOD3..LOD0
- for (unsigned char l = 4; l-- > 0; )
- {
- for (size_t yy = 0; yy < size_t(8 >> l); yy++)
- {
- size_t yc = (y >> l) + yy;
- if (yc >= ((nCellsY + (1 << l) - 1) >> l))
- break;
- for (size_t xx = 0; xx < size_t(8 >> l); xx++)
- {
- size_t xc = (x >> l) + xx;
- if (xc >= ((nCellsX + (1 << l) - 1) >> l))
- break;
- size_t n = yc * ((nCellsX + (1 << l) - 1) >> l) + xc;
- unsigned short *p =
- curTileData + (((yy << l) << 17) + ((xx << l) << 7));
- loadBlock(p, n, l, 0);
- if (l != 1)
- loadBlock(p, n, l, 1);
- }
- }
- }
- }
- BTDFile::BTDFile(const char *fileName)
- : FileBuffer(fileName)
- {
- if (!checkType(readUInt32(), "BTDB"))
- throw std::runtime_error(std::string("input file format is not BTD"));
- if (readUInt32() != 6U)
- throw std::runtime_error(std::string("unsupported BTD format version"));
- // TODO: check header data for errors
- worldHeightMin = readFloat();
- worldHeightMax = readFloat();
- heightMapResX = readUInt32();
- heightMapResY = readUInt32();
- cellMinX = readInt32();
- cellMinY = readInt32();
- cellMaxX = readInt32();
- cellMaxY = readInt32();
- nCellsX = size_t(cellMaxX + 1 - cellMinX);
- nCellsY = size_t(cellMaxY + 1 - cellMinY);
- ltexCnt = readUInt32();
- ltexOffs = filePos;
- for (size_t i = 0; i < ltexCnt; i++)
- (void) readUInt32();
- cellHeightMinMaxMapOffs = filePos;
- filePos = filePos + ((nCellsY * nCellsX) << 3);
- ltexMapOffs = filePos;
- filePos = filePos + ((nCellsY * nCellsX) << 5);
- gcvrCnt = readUInt32();
- gcvrOffs = filePos;
- for (size_t i = 0; i < gcvrCnt; i++)
- (void) readUInt32();
- gcvrMapOffs = filePos;
- filePos = filePos + ((nCellsY * nCellsX) << 5);
- heightMapLOD4 = filePos;
- filePos = filePos + ((nCellsY * nCellsX) << 7);
- landTexturesLOD4 = filePos;
- filePos = filePos + ((nCellsY * nCellsX) << 7);
- normalsLOD4 = filePos;
- filePos = filePos + ((nCellsY * nCellsX) << 7);
- zlibBlocksTableOffs = filePos;
- zlibBlkTableOffsLOD3 = filePos;
- filePos = filePos + (((nCellsY + 7) >> 3) * ((nCellsX + 7) >> 3) * 2 * 8);
- zlibBlkTableOffsLOD2 = filePos;
- filePos = filePos + (((nCellsY + 3) >> 2) * ((nCellsX + 3) >> 2) * 2 * 8);
- zlibBlkTableOffsLOD1 = filePos;
- filePos = filePos + (((nCellsY + 1) >> 1) * ((nCellsX + 1) >> 1) * 8);
- zlibBlkTableOffsLOD0 = filePos;
- filePos = filePos + (nCellsY * nCellsX * 2 * 8);
- zlibBlocksDataOffs = filePos;
- nCompressedBlocks = (filePos - zlibBlocksTableOffs) >> 3;
- (void) readUInt8();
- curTileX = 0x7FFFFFF0;
- curTileY = 0x7FFFFFF0;
- prvTileX = 0x7FFFFFF0;
- prvTileY = 0x7FFFFFF0;
- tileBuf.resize(128 * 128 * 4 * 8 * 8 * 2, 0);
- curTileData = &(tileBuf.front());
- prvTileData = curTileData + (128 * 128 * 4 * 8 * 8);
- }
- BTDFile::~BTDFile()
- {
- }
- unsigned int BTDFile::getLandTexture(size_t n)
- {
- if (n >= ltexCnt)
- return 0U;
- filePos = ltexOffs + (n << 2);
- return readUInt32();
- }
- unsigned int BTDFile::getGroundCover(size_t n)
- {
- if (n >= gcvrCnt)
- return 0U;
- filePos = gcvrOffs + (n << 2);
- return readUInt32();
- }
- void BTDFile::getCellHeightMap(float *buf, int cellX, int cellY)
- {
- loadTile(cellX, cellY);
- size_t x0 = size_t((cellX - cellMinX) & 7) << 7;
- size_t y0 = size_t((cellY - cellMinY) & 7) << 7;
- for (size_t yc = 0; yc < 128; yc++)
- {
- for (size_t xc = 0; xc < 128; xc++)
- {
- int tmp = int(curTileData[((y0 + yc) << 10) + x0 + xc]);
- float z = float(tmp) * float(1.0 / 65535.0);
- z = z * (worldHeightMax - worldHeightMin) + worldHeightMin;
- buf[(yc << 7) + xc] = z;
- }
- }
- }
- void BTDFile::getCellLandTexture(unsigned char *buf, int cellX, int cellY)
- {
- loadTile(cellX, cellY);
- size_t x = size_t(cellX - cellMinX);
- size_t y = size_t(cellY - cellMinY);
- size_t x0 = (x & 7) << 7;
- size_t y0 = (y & 7) << 7;
- unsigned char l[8];
- for (size_t i = 0; i < 8; i++)
- l[i] = 0xFF;
- for (size_t q = 0; q < 4; q++)
- {
- unsigned char defaultTexture = 0xFF;
- size_t offs =
- ((y << 1) | (q >> 1)) * (nCellsX << 1) + ((x << 1) | (q & 1));
- filePos = (offs << 3) + ltexMapOffs;
- for (size_t i = 0; i < 8; i++)
- {
- unsigned char tmp = readUInt8();
- if (tmp == 0 || tmp > ltexCnt)
- tmp = 0xFF;
- else
- tmp = (unsigned char) (ltexCnt - tmp);
- l[i] = tmp;
- if (tmp != 0xFF)
- defaultTexture = tmp;
- }
- for (size_t yy = 0; yy < 64; yy++)
- {
- for (size_t xx = 0; xx < 64; xx++)
- {
- size_t xc = ((q & 1) << 6) | xx;
- size_t yc = ((q & 2) << 5) | yy;
- unsigned char *bufp = buf + (((yc << 7) | xc) << 4);
- bufp[0] = defaultTexture;
- for (size_t i = 1; i < 16; i++)
- bufp[i] = ((i < 11 && (i & 1) != 0) ? 0xFF : 0x00);
- unsigned int tmp =
- curTileData[((y0 + yc) << 10) + x0 + xc + 0x00100000];
- for (int i = 4; i >= 0; i--)
- {
- if ((tmp & 0x7000) != 0U && l[i] != 0xFF)
- {
- bufp[1] = l[i];
- bufp[2] = (unsigned char) ((((tmp >> 12) & 7) * 73) >> 1);
- bufp = bufp + 2;
- }
- tmp = tmp << 3;
- }
- }
- }
- }
- }
- void BTDFile::getCellGroundCover(unsigned char *buf, int cellX, int cellY)
- {
- loadTile(cellX, cellY);
- size_t x = size_t(cellX - cellMinX);
- size_t y = size_t(cellY - cellMinY);
- size_t x0 = (x & 7) << 7;
- size_t y0 = (y & 7) << 7;
- unsigned char g[8];
- for (size_t i = 0; i < 8; i++)
- g[i] = 0xFF;
- for (size_t q = 0; q < 4; q++)
- {
- size_t offs =
- ((y << 1) | (q >> 1)) * (nCellsX << 1) + ((x << 1) | (q & 1));
- filePos = (offs << 3) + gcvrMapOffs;
- for (size_t i = 0; i < 8; i++)
- {
- unsigned char tmp = readUInt8();
- if (tmp >= gcvrCnt)
- tmp = 0xFF;
- g[i] = tmp;
- }
- for (size_t yy = 0; yy < 64; yy++)
- {
- for (size_t xx = 0; xx < 64; xx++)
- {
- size_t xc = ((q & 1) << 6) | xx;
- size_t yc = ((q & 2) << 5) | yy;
- unsigned char *bufp = buf + (((yc << 7) | xc) << 3);
- unsigned int tmp =
- curTileData[((y0 + yc) << 10) + x0 + xc + 0x00200000];
- for (int i = 0; i < 8; i++)
- bufp[i] = 0xFF;
- for (int i = 7; i >= 0; i--)
- {
- if ((tmp & (1U << i)) != 0U && g[i] != 0xFF)
- *(bufp++) = g[i];
- }
- }
- }
- }
- }
- void BTDFile::getCellNormals(unsigned short *buf, int cellX, int cellY)
- {
- loadTile(cellX, cellY);
- size_t x = size_t(cellX - cellMinX);
- size_t y = size_t(cellY - cellMinY);
- size_t x0 = (x & 7) << 7;
- size_t y0 = (y & 7) << 7;
- for (size_t yc = 0; yc < 128; yc = yc + 4)
- {
- for (size_t xc = 0; xc < 128; xc = xc + 4)
- {
- unsigned short *bufp = buf + ((yc << 7) | xc);
- unsigned short tmp =
- curTileData[((y0 + yc) << 10) + x0 + xc + 0x00300000];
- for (int i = 0; i < 16; i++)
- bufp[((i >> 2) << 7) | (i & 3)] = tmp;
- }
- }
- }
- static inline unsigned char blendDithered(unsigned char a, unsigned char b,
- unsigned char opacityB, int x, int y)
- {
- static const unsigned char t[64] =
- {
- 0, 48, 12, 60, 3, 51, 15, 63, 32, 16, 44, 28, 35, 19, 47, 31,
- 8, 56, 4, 52, 11, 59, 7, 55, 40, 24, 36, 20, 43, 27, 39, 23,
- 2, 50, 14, 62, 1, 49, 13, 61, 34, 18, 46, 30, 33, 17, 45, 29,
- 10, 58, 6, 54, 9, 57, 5, 53, 42, 26, 38, 22, 41, 25, 37, 21
- };
- unsigned char d = t[((y & 7) << 3) | (x & 7)];
- return (((((unsigned int) opacityB + 2) >> 2) + d) < 64 ? a : b);
- }
- int main(int argc, char **argv)
- {
- if (argc != 8 && argc != 9)
- {
- std::fprintf(stderr, "Usage: btddump INFILE.BTD OUTFILE FMT "
- "XMIN YMIN XMAX YMAX [LOD]\n");
- std::fprintf(stderr, " FMT = 0: raw 16-bit height map\n");
- std::fprintf(stderr, " FMT = 1: dithered 8-bit height map\n");
- std::fprintf(stderr, " FMT = 2: raw landscape textures "
- "(8 bytes / vertex)\n");
- std::fprintf(stderr, " FMT = 3: dithered 8-bit landscape texture\n");
- std::fprintf(stderr, " FMT = 4: raw ground cover (8 bytes / vertex)\n");
- std::fprintf(stderr, " FMT = 5: dithered 8-bit ground cover\n");
- std::fprintf(stderr, " FMT = 6: raw 16-bit normals\n");
- std::fprintf(stderr, " FMT = 7: normals in 24-bit RGB format\n");
- return 1;
- }
- std::FILE *outFile = (std::FILE *) 0;
- try
- {
- BTDFile btdFile(argv[1]);
- int outFmt = std::atoi(argv[3]);
- if (outFmt < 0 || outFmt > 7)
- throw std::runtime_error(std::string("invalid output format"));
- int xMin = std::atoi(argv[4]);
- int yMin = std::atoi(argv[5]);
- int xMax = std::atoi(argv[6]);
- int yMax = std::atoi(argv[7]);
- if (xMin < btdFile.getCellMinX() || xMax > btdFile.getCellMaxX() ||
- xMin > xMax)
- {
- throw std::runtime_error(std::string("invalid X range"));
- }
- if (yMin < btdFile.getCellMinY() || yMax > btdFile.getCellMaxY() ||
- yMin > yMax)
- {
- throw std::runtime_error(std::string("invalid Y range"));
- }
- if (outFmt == 0 || outFmt == 1)
- {
- std::printf("Minimum height = %f, maximum height = %f\n",
- btdFile.getMinHeight(), btdFile.getMaxHeight());
- }
- if (outFmt == 2 || outFmt == 3)
- {
- for (size_t i = 0; true; i++)
- {
- unsigned int n = btdFile.getLandTexture(i);
- if (!n)
- break;
- std::printf("Land texture %d: 0x%08X\n", int(i), n);
- }
- }
- if (outFmt == 4 || outFmt == 5)
- {
- for (size_t i = 0; true; i++)
- {
- unsigned int n = btdFile.getGroundCover(i);
- if (!n)
- break;
- std::printf("Ground cover %d: 0x%08X\n", int(i), n);
- }
- }
- int l = (outFmt < 6 ? 0 : 2);
- if (argc > 8)
- {
- l = std::atoi(argv[8]);
- if (l < (outFmt < 6 ? 0 : 2) || l > 4)
- throw std::runtime_error(std::string("invalid level of detail"));
- }
- #if defined(_WIN32) || defined(_WIN64)
- outFile = fopen64(argv[2], "wb");
- #else
- outFile = std::fopen(argv[2], "wb");
- #endif
- if (!outFile)
- throw std::runtime_error(std::string("error opening output file"));
- std::vector< unsigned char > outBuf;
- std::vector< float > heightBuf(16384, 0.0f);
- std::vector< unsigned short > normalsBuf(0x00020000, 0);
- unsigned char *ltexBuf =
- reinterpret_cast< unsigned char * >(&(normalsBuf.front()));
- unsigned char *gcvrBuf = ltexBuf;
- int x0 = xMin;
- int y0 = yMax;
- int x = xMin;
- int y = yMax;
- while (true)
- {
- static const size_t outFmtDataSizes[8] = { 2, 1, 8, 1, 8, 1, 2, 3 };
- size_t w = size_t(xMax + 1 - xMin);
- if (!outBuf.size())
- {
- size_t h = size_t(((y0 - btdFile.getCellMinY()) & 7) + 1);
- if (h > size_t(y0 + 1 - yMin))
- h = size_t(y0 + 1 - yMin);
- outBuf.resize(w * h * (outFmtDataSizes[outFmt] << (14 - (l << 1))), 0);
- }
- switch (outFmt >> 1)
- {
- case 0:
- btdFile.getCellHeightMap(&(heightBuf.front()), x, y);
- break;
- case 1:
- btdFile.getCellLandTexture(ltexBuf, x, y);
- break;
- case 2:
- btdFile.getCellGroundCover(gcvrBuf, x, y);
- break;
- case 3:
- btdFile.getCellNormals(&(normalsBuf.front()), x, y);
- break;
- }
- for (size_t yy = 0; yy < 128; yy = yy + size_t(1 << l))
- {
- size_t offs = (size_t((y0 - y) << 7) | (127 - yy)) >> l;
- offs = offs * (w << (7 - l)) + (size_t((x - xMin) << 7) >> l);
- unsigned char *p = &(outBuf.front()) + (offs * outFmtDataSizes[outFmt]);
- for (size_t xx = 0; xx < 128; xx = xx + size_t(1 << l))
- {
- unsigned int tmp = 0U;
- switch (outFmt)
- {
- case 0: // raw height map
- case 1: // dithered 8-bit height map
- {
- float z = heightBuf[(yy << 7) | xx];
- z = (z - btdFile.getMinHeight())
- / (btdFile.getMaxHeight() - btdFile.getMinHeight());
- z = (z > 0.0f ? (z < 1.0f ? z : 1.0f) : 0.0f);
- tmp = (unsigned int) (int(z * 65535.0f + 0.5f));
- }
- if (outFmt == 0)
- {
- p[0] = (unsigned char) (tmp & 0xFF);
- p[1] = (unsigned char) (tmp >> 8);
- }
- else
- {
- tmp = (tmp * 0xFF01U) >> 16;
- tmp = blendDithered((unsigned char) (tmp >> 8),
- (unsigned char) ((tmp + 255) >> 8),
- (unsigned char) (tmp & 0xFF),
- int(xx >> l), int((127 - yy) >> l));
- p[0] = (unsigned char) tmp;
- }
- break;
- case 2: // raw land textures
- p[0] = ltexBuf[((yy << 7) | xx) << 4];
- for (size_t i = 0; i < 5; i++)
- {
- const unsigned char *ltexPtr =
- ltexBuf + ((((yy << 7) | xx) << 4) + (i << 1));
- p[i + 1] = ltexPtr[1];
- tmp = (tmp >> 3) | ((unsigned int) (ltexPtr[2] & 0xE0) << 7);
- }
- p[6] = (unsigned char) (tmp & 0xFF);
- p[7] = (unsigned char) (tmp >> 8);
- break;
- case 3: // dithered 8-bit land texture
- tmp = ltexBuf[((yy << 7) | xx) << 4];
- for (size_t i = 0; i < 5; i++)
- {
- const unsigned char *ltexPtr =
- ltexBuf + ((((yy << 7) | xx) << 4) + (i << 1));
- tmp = blendDithered((unsigned char) tmp, ltexPtr[1], ltexPtr[2],
- int(xx >> l), int((127 - yy) >> l));
- }
- p[0] = (unsigned char) tmp;
- break;
- case 4: // raw ground cover
- for (size_t i = 0; i < 8; i++)
- p[i] = gcvrBuf[(((yy << 7) | xx) << 3) + i];
- break;
- case 5: // dithered 8-bit ground cover
- tmp = 0xFF;
- {
- static const unsigned char ditherWeights[16] =
- {
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 8, 8
- };
- size_t n = 0;
- while (n < 8 && gcvrBuf[(((yy << 7) | xx) << 3) + n] != 0xFF)
- n++;
- unsigned char d = 0xFF;
- for (size_t i = n; i-- > 0; )
- {
- unsigned char g = gcvrBuf[(((yy << 7) | xx) << 3) + i];
- if (tmp == 0xFF)
- {
- tmp = g;
- continue;
- }
- d = d - (ditherWeights[i + 17 - (n << 1)] << 5);
- tmp = blendDithered((unsigned char) tmp, g, d,
- int(xx >> l), int((127 - yy) >> l));
- }
- }
- p[0] = (unsigned char) tmp;
- break;
- case 6: // raw normals
- tmp = normalsBuf[(yy << 7) | xx];
- p[0] = (unsigned char) (tmp & 0xFF);
- p[1] = (unsigned char) (tmp >> 8);
- break;
- case 7: // normals in 24-bit RGB format
- tmp = normalsBuf[(yy << 7) | xx];
- p[0] = (unsigned char) ((tmp & 0x001FU) << 3);
- p[1] = (unsigned char) ((tmp & 0x03E0U) >> 2);
- p[2] = (unsigned char) ((tmp & 0xFC00U) >> 8);
- break;
- }
- p = p + outFmtDataSizes[outFmt];
- }
- }
- x++;
- if (x > xMax || ((x - btdFile.getCellMinX()) & 7) == 0)
- {
- y--;
- if (y < yMin || ((y - btdFile.getCellMinY()) & 7) == 7)
- {
- if (x > xMax)
- {
- if (std::fwrite(&(outBuf.front()),
- sizeof(unsigned char), outBuf.size(), outFile)
- != outBuf.size() || std::fflush(outFile) != 0)
- {
- throw std::runtime_error(std::string(
- "error writing output file"));
- }
- outBuf.clear();
- x = xMin;
- if (y < yMin)
- break;
- y0 = y;
- }
- y = y0;
- x0 = x;
- }
- x = x0;
- }
- }
- std::fclose(outFile);
- }
- catch (std::exception& e)
- {
- if (outFile)
- std::fclose(outFile);
- std::fprintf(stderr, "btddump: %s\n", e.what());
- return 1;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement