diff --git a/tileconv/Makefile b/tileconv/Makefile index b5a3709..946c4d1 100644 --- a/tileconv/Makefile +++ b/tileconv/Makefile @@ -25,6 +25,8 @@ else ifeq ($(shell uname -s),Darwin) # A few hacks to enable proper threading support CXXFLAGS += -D_GLIBCXX_USE_NANOSLEEP + # Don't assume that standard libraries are available on the target system + LDFLAGS += -static-libstdc++ -static-libgcc else # Nothing to do for Linux (yet) endif diff --git a/tileconv/README b/tileconv/README index 5b2b681..1c50532 100644 --- a/tileconv/README +++ b/tileconv/README @@ -1,7 +1,7 @@ TILECONV ~~~~~~~~ -Version: 0.5 +Version: 0.5.1 Author: Argent77 This tool allows you to compress or decompress TIS and MOS files provided by @@ -128,3 +128,6 @@ v0.5 (2014-09-18) * Added TIZ/MOZ decompression support * Option -T is recognized by option -I * Incomplete output files are deleted on error + +v0.5.1 (2015-05-10) + * Fixed potential issues with the Mac OS X version diff --git a/tileconv/fileio.cpp b/tileconv/fileio.cpp index da0817c..f02027f 100644 --- a/tileconv/fileio.cpp +++ b/tileconv/fileio.cpp @@ -83,6 +83,7 @@ File::File(const char *fileName, const char *mode) noexcept } } + File::File(const char *fileName, const char *mode, int bufferSize) noexcept : m_file(0) , m_fileName() @@ -100,6 +101,7 @@ File::File(const char *fileName, const char *mode, int bufferSize) noexcept } } + File::~File() noexcept { if (m_file != nullptr) { @@ -116,6 +118,7 @@ File::~File() noexcept } } + bool File::reopen(const char *fileName, const char *mode) noexcept { if (m_file) { @@ -132,6 +135,7 @@ bool File::reopen(const char *fileName, const char *mode) noexcept return false; } + bool File::flush() noexcept { if (m_file) { @@ -140,6 +144,7 @@ bool File::flush() noexcept return false; } + std::size_t File::read(void *buffer, std::size_t size, std::size_t count) noexcept { if (m_file) { @@ -148,6 +153,7 @@ std::size_t File::read(void *buffer, std::size_t size, std::size_t count) noexce return 0; } + std::size_t File::write(const void *buffer, std::size_t size, std::size_t count) noexcept { if (m_file) { @@ -156,6 +162,7 @@ std::size_t File::write(const void *buffer, std::size_t size, std::size_t count) return 0; } + int File::getc() noexcept { if (m_file) { @@ -164,6 +171,7 @@ int File::getc() noexcept return EOF; } + char* File::gets(char *str, int count) noexcept { if (m_file) { @@ -172,6 +180,7 @@ char* File::gets(char *str, int count) noexcept return NULL; } + int File::putc(int ch) noexcept { if (m_file) { @@ -180,6 +189,7 @@ int File::putc(int ch) noexcept return EOF; } + int File::puts(const char *str) noexcept { if (m_file) { @@ -188,6 +198,7 @@ int File::puts(const char *str) noexcept return EOF; } + int File::ungetc(int ch) noexcept { if (m_file) { @@ -196,6 +207,7 @@ int File::ungetc(int ch) noexcept return EOF; } + long File::tell() noexcept { if (m_file) { @@ -204,6 +216,7 @@ long File::tell() noexcept return -1L; } + bool File::getpos(std::fpos_t *pos) noexcept { if (m_file) { @@ -212,6 +225,7 @@ bool File::getpos(std::fpos_t *pos) noexcept return false; } + bool File::seek(long offset, int origin) noexcept { if (m_file) { @@ -220,6 +234,7 @@ bool File::seek(long offset, int origin) noexcept return false; } + bool File::setpos(const std::fpos_t *pos) noexcept { if (m_file) { @@ -228,6 +243,7 @@ bool File::setpos(const std::fpos_t *pos) noexcept return false; } + void File::rewind() noexcept { if (m_file) { @@ -235,6 +251,7 @@ void File::rewind() noexcept } } + void File::clearerr() noexcept { if (m_file) { @@ -242,6 +259,7 @@ void File::clearerr() noexcept } } + bool File::eof() noexcept { if (m_file) { @@ -250,6 +268,7 @@ bool File::eof() noexcept return true; } + bool File::error() noexcept { if (m_file) { @@ -258,6 +277,7 @@ bool File::error() noexcept return true; } + void File::perror(const char *s) noexcept { std::perror(s); diff --git a/tileconv/fileio.h b/tileconv/fileio.h index 335b302..89a8197 100644 --- a/tileconv/fileio.h +++ b/tileconv/fileio.h @@ -134,6 +134,13 @@ class File /** Returns whether current file is writable. */ bool isWriteEnabled() const noexcept; +private: + /** Not copyable. */ + File(const File &) = delete; + + /** Not assignable. */ + File& operator=(const File &) = delete; + private: std::FILE *m_file; // current file handle std::string m_fileName; // filename diff --git a/tileconv/graphics.cpp b/tileconv/graphics.cpp index a14753b..ed41e0f 100644 --- a/tileconv/graphics.cpp +++ b/tileconv/graphics.cpp @@ -48,7 +48,9 @@ const char Graphics::HEADER_VERSION_V1[4] = {'V', '1', ' ', ' '}; const char Graphics::HEADER_VERSION_V2[4] = {'V', '2', ' ', ' '}; const char Graphics::HEADER_VERSION_V1_0[4] = {'V', '1', '.', '0'}; -const unsigned Graphics::MAX_PROGRESS = 69; +const unsigned Graphics::MAX_PROGRESS = 69; +const unsigned Graphics::MAX_POOL_TILES = 64; + Graphics::Graphics(const Options &options) noexcept : m_options(options) @@ -66,86 +68,16 @@ bool Graphics::tisToTBC(const std::string &inFile, const std::string &outFile) n if (!inFile.empty() && !outFile.empty() && inFile != outFile) { File fin(inFile.c_str(), "rb"); if (!fin.error()) { - char sig[4], ver[4]; - uint32_t tileCount, tileSize, headerSize, tileDim; - bool isHeaderless = false; + uint32_t tileCount; // parsing TIS header - if (fin.read(sig, 1, 4) != 4) return false; - if (std::strncmp(sig, HEADER_TIS_SIGNATURE, 4) != 0) { - if (getOptions().assumeTis()) { - fin.seek(0L, SEEK_SET); - isHeaderless = true; - } else { - std::printf("Invalid TIS signature\n"); - return false; - } - } - - if (!isHeaderless) { - if (fin.read(ver, 1, 4) != 4) return false; - if (std::strncmp(ver, HEADER_VERSION_V2, 4) == 0) { - if (!getOptions().isSilent()) { - std::printf("Warning: Incorrect TIS version 2 found. Converting anyway.\n"); - } - } else if (std::strncmp(ver, HEADER_VERSION_V1, 4) != 0) { - std::printf("Invalid TIS version\n"); - return false; - } - - if (fin.read(&tileCount, 4, 1) != 1) return false; - tileCount = get32u_le(&tileCount); - if (tileCount == 0) { - std::printf("No tiles found\n"); - return false; - } - - if (fin.read(&tileSize, 4, 1) != 1) return false; - tileSize = get32u_le(&tileSize); - if (tileSize != 0x1400) { - if (tileSize == 0x000c) { - std::printf("PVRZ-based TIS files are not supported\n"); - } else { - std::printf("Invalid tile size\n"); - } - return false; - } - - if (fin.read(&headerSize, 4, 1) != 1) return false; - headerSize = get32u_le(&headerSize); - if (headerSize < 0x18) { - std::printf("Invalid header size\n"); - return false; - } - - if (fin.read(&tileDim, 4, 1) != 1) return false; - tileDim = get32u_le(&tileDim); - if (tileDim != 0x40) { - std::printf("Invalid tile dimensions\n"); - return false; - } - } else { - long size = fin.getsize(); - fin.seek(0L, SEEK_SET); - if (size < 0L) { - std::printf("Error reading input file\n"); - return false; - } else if ((size % 5120) != 0) { - std::printf("Headerless TIS has wrong file size\n"); - return false; - } else { - if (!getOptions().isSilent()) std::printf("Warning: Headerless TIS file detected\n"); - tileSize = 0x1400; - tileDim = 0x40; - tileCount = (uint32_t)(size / tileSize); - } - } + if (!readTIS(fin, tileCount)) return false; File fout(outFile.c_str(), "wb"); fout.setDeleteOnClose(true); if (!fout.error()) { uint32_t v32; - uint32_t tileSizeIndexed = tileDim*tileDim; // indexed size of the tile + uint32_t tileSizeIndexed = TILE_DIMENSION*TILE_DIMENSION; // indexed size of the tile // writing TBC header if (fout.write(HEADER_TBC_SIGNATURE, 1, sizeof(HEADER_TBC_SIGNATURE)) != sizeof(HEADER_TBC_SIGNATURE)) return false; @@ -159,60 +91,39 @@ bool Graphics::tisToTBC(const std::string &inFile, const std::string &outFile) n if (getOptions().getVerbosity() == 1) std::printf("Converting"); // converting tiles - ThreadPoolPtr pool = createThreadPool(*this, getOptions().getThreads(), 64); - unsigned nextTileIdx = 0, curProgress = 0; + ThreadPoolPtr pool = createThreadPool(getOptions().getThreads(), MAX_POOL_TILES); double ratioCount = 0.0; // counts the compression ratios of all tiles - for (unsigned tileIdx = 0; tileIdx < tileCount; tileIdx++) { - if (getOptions().isVerbose()) std::printf("Converting tile #%d\n", tileIdx); - - // writing converted tiles to disk - while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { - TileDataPtr retVal = pool->getResult(); - if (retVal == nullptr || retVal->isError()) { - if (retVal != nullptr && !retVal->getErrorMsg().empty()) { - std::printf("\n%s", retVal->getErrorMsg().c_str()); - } + unsigned tileIdx = 0, nextTileIdx = 0, curProgress = 0; + while (tileIdx < tileCount || !pool->finished()) { + // creating new tile data object + if (tileIdx < tileCount) { + if (getOptions().isVerbose()) std::printf("Converting tile #%d\n", tileIdx); + BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); + BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); + BytePtr ptrDeflated(new uint8_t[MAX_TILE_SIZE_32*2], std::default_delete()); + TileDataPtr tileData(new TileData(getOptions())); + tileData->setEncoding(true); + tileData->setIndex(tileIdx); + tileData->setType(Options::GetEncodingCode(getOptions().getEncoding(), getOptions().isDeflate())); + tileData->setPaletteData(ptrPalette); + tileData->setIndexedData(ptrIndexed); + tileData->setDeflatedData(ptrDeflated); + tileData->setWidth(TILE_DIMENSION); + tileData->setHeight(TILE_DIMENSION); + // reading paletted tile + if (fin.read(tileData->getPaletteData().get(), 1, PALETTE_SIZE) != PALETTE_SIZE) { return false; } - double ratio = 0.0; - if (!writeEncodedTile(retVal, fout, ratio)) { + if (fin.read(tileData->getIndexedData().get(), 1, tileSizeIndexed) != tileSizeIndexed) { return false; } - if (getOptions().getVerbosity() == 1) { - curProgress = showProgress(nextTileIdx, tileCount, curProgress, MAX_PROGRESS, '.'); - } - ratioCount += ratio; - nextTileIdx++; - } - - // creating new tile data object - BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); - BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); - BytePtr ptrDeflated(new uint8_t[MAX_TILE_SIZE_32*2], std::default_delete()); - TileDataPtr tileData(new TileData(getOptions())); - tileData->setEncoding(true); - tileData->setIndex(tileIdx); - tileData->setType(Options::GetEncodingCode(getOptions().getEncoding(), getOptions().isDeflate())); - tileData->setPaletteData(ptrPalette); - tileData->setIndexedData(ptrIndexed); - tileData->setDeflatedData(ptrDeflated); - tileData->setWidth(tileDim); - tileData->setHeight(tileDim); - // reading paletted tile - if (fin.read(tileData->getPaletteData().get(), 1, PALETTE_SIZE) != PALETTE_SIZE) { - return false; - } - if (fin.read(tileData->getIndexedData().get(), 1, tileSizeIndexed) != tileSizeIndexed) { - return false; + pool->addTileData(tileData); + tileIdx++; } - pool->addTileData(tileData); - } - // retrieving the remaining tile data blocks in queue - while (!pool->finished()) { + // processing converted tiles while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { + (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { TileDataPtr retVal = pool->getResult(); if (retVal == nullptr || retVal->isError()) { if (retVal != nullptr && !retVal->getErrorMsg().empty()) { @@ -230,7 +141,9 @@ bool Graphics::tisToTBC(const std::string &inFile, const std::string &outFile) n ratioCount += ratio; nextTileIdx++; } - pool->waitForResult(); + if (tileIdx >= tileCount) { + pool->waitForResult(); + } } if (getOptions().getVerbosity() == 1) std::printf("\n"); @@ -261,31 +174,10 @@ bool Graphics::tbcToTIS(const std::string &inFile, const std::string &outFile) n if (!inFile.empty() && !outFile.empty() && inFile != outFile) { File fin(inFile.c_str(), "rb"); if (!fin.error()) { - char sig[4], ver[4]; - uint32_t compType, tileCount; + unsigned compType, tileCount; // parsing TBC header - if (fin.read(sig, 1, 4) != 4) return false;; - if (std::strncmp(sig, HEADER_TBC_SIGNATURE, 4) != 0) { - std::printf("Invalid TBC signature\n"); - return false; - } - - if (fin.read(ver, 1, 4) != 4) return false; - if (std::strncmp(ver, HEADER_VERSION_V1_0, 4) != 0) { - std::printf("Unsupported TBC version\n"); - return false; - } - - if (fin.read(&compType, 4, 1) != 1) return false; - compType = get32u_le(&compType); - - if (fin.read(&tileCount, 4, 1) != 1) return false; - tileCount = get32u_le(&tileCount); - if (tileCount == 0) { - std::printf("No tiles found\n"); - return false; - } + if (!readTBC(fin, compType, tileCount)) return false; File fout(outFile.c_str(), "wb"); fout.setDeleteOnClose(true); @@ -310,53 +202,35 @@ bool Graphics::tbcToTIS(const std::string &inFile, const std::string &outFile) n } if (getOptions().getVerbosity() == 1) std::printf("Converting"); - ThreadPoolPtr pool = createThreadPool(*this, getOptions().getThreads(), 64); - uint32_t nextTileIdx = 0, curProgress = 0; - for (uint32_t tileIdx = 0; tileIdx < tileCount; tileIdx++) { - // writing converted tiles to disk - while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { - TileDataPtr retVal = pool->getResult(); - if (retVal == nullptr || retVal->isError()) { - if (retVal != nullptr && !retVal->getErrorMsg().empty()) { - std::printf("\n%s", retVal->getErrorMsg().c_str()); - } - return false; - } - if (!writeDecodedTisTile(retVal, fout)) { + ThreadPoolPtr pool = createThreadPool(getOptions().getThreads(), MAX_POOL_TILES); + unsigned tileIdx = 0, nextTileIdx = 0, curProgress = 0; + while (tileIdx < tileCount || !pool->finished()) { + // creating new tile data object + if (tileIdx < tileCount) { + uint32_t chunkSize; + if (fin.read(&v32, 4, 1) != 1) return false; + chunkSize = get32u_le(&v32); + if (chunkSize == 0) { + std::printf("\nInvalid block size found for tile #%d\n", tileIdx); return false; } - if (getOptions().getVerbosity() == 1) { - curProgress = showProgress(nextTileIdx, tileCount, curProgress, MAX_PROGRESS, '.'); - } - nextTileIdx++; - } - - // creating new tile data object - uint32_t chunkSize; - if (fin.read(&v32, 4, 1) != 1) return false; - chunkSize = get32u_le(&v32); - if (chunkSize == 0) { - std::printf("\nInvalid block size found for tile #%d\n", tileIdx); - return false; + BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); + BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); + BytePtr ptrDeflated(new uint8_t[chunkSize], std::default_delete()); + if (fin.read(ptrDeflated.get(), 1, chunkSize) != chunkSize) return false; + TileDataPtr tileData(new TileData(getOptions())); + tileData->setEncoding(false); + tileData->setIndex(tileIdx); + tileData->setType(compType); + tileData->setPaletteData(ptrPalette); + tileData->setIndexedData(ptrIndexed); + tileData->setDeflatedData(ptrDeflated); + tileData->setSize(chunkSize); + pool->addTileData(tileData); + tileIdx++; } - BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); - BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); - BytePtr ptrDeflated(new uint8_t[chunkSize], std::default_delete()); - if (fin.read(ptrDeflated.get(), 1, chunkSize) != chunkSize) return false; - TileDataPtr tileData(new TileData(getOptions())); - tileData->setEncoding(false); - tileData->setIndex(tileIdx); - tileData->setType(compType); - tileData->setPaletteData(ptrPalette); - tileData->setIndexedData(ptrIndexed); - tileData->setDeflatedData(ptrDeflated); - tileData->setSize(chunkSize); - pool->addTileData(tileData); - } - // retrieving the remaining tile data blocks in queue - while (!pool->finished()) { + // writing converted tiles to disk while (pool->hasResult() && pool->peekResult() != nullptr && (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { TileDataPtr retVal = pool->getResult(); @@ -374,7 +248,9 @@ bool Graphics::tbcToTIS(const std::string &inFile, const std::string &outFile) n } nextTileIdx++; } - pool->waitForResult(); + if (tileIdx >= tileCount) { + pool->waitForResult(); + } } if (getOptions().getVerbosity() == 1) std::printf("\n"); @@ -404,129 +280,13 @@ bool Graphics::mosToMBC(const std::string &inFile, const std::string &outFile) n if (!inFile.empty() && !outFile.empty() && inFile != outFile) { File fin(inFile.c_str(), "rb"); if (!fin.error()) { - char sig[4], ver[4]; - uint32_t mosSize, tileDim, palOfs; - uint16_t mosWidth, mosHeight, mosCols, mosRows; - BytePtr mosData(nullptr, std::default_delete()); - - // loading MOS/MOSC input file - if (fin.read(sig, 1, 4) != 4) return false;; - if (std::strncmp(sig, HEADER_MOSC_SIGNATURE, 4) == 0) { // decompressing MOSC - uint32_t moscSize; - Compression compression; - - // getting MOSC file size - moscSize = fin.getsize(); - if (moscSize <= 12) { - std::printf("Invalid MOSC size\n"); - return false; - } - moscSize -= 12; // removing header size - - fin.seek(4, SEEK_SET); - if (fin.read(&ver, 1, 4) != 4) return false; - if (std::strncmp(ver, HEADER_VERSION_V1, 4) != 0) { - std::printf("Invalid MOSC version\n"); - return false; - } - - if (fin.read(&mosSize, 4, 1) != 1) return false; - mosSize = get32u_le(&mosSize); - if (mosSize < 24) { - std::printf("MOS size too small\n"); - return false; - } - BytePtr moscData(new uint8_t[moscSize], std::default_delete()); - if (fin.read(moscData.get(), 1, moscSize) < moscSize) { - std::printf("Incomplete or corrupted MOSC file\n"); - return false; - } + unsigned mosWidth, mosHeight, mosCols, mosRows, palOfs; + BytePtr mosData(nullptr); - mosData.reset(new uint8_t[mosSize], std::default_delete()); - uint32_t size = compression.inflate(moscData.get(), moscSize, mosData.get(), mosSize); - if (size != mosSize) { - std::printf("Error while decompressing MOSC input file\n"); - return false; - } - } else if (std::strncmp(sig, HEADER_MOS_SIGNATURE, 4) == 0) { // loading MOS data - mosSize = fin.getsize(); - if (mosSize < 24) { - std::printf("MOS size too small\n"); - return false; - } - fin.seek(0, SEEK_SET); - mosData.reset(new uint8_t[mosSize], std::default_delete()); - if (fin.read(mosData.get(), 1, mosSize) != mosSize) return false; - } else { - std::printf("Invalid MOS signature\n"); - return false; - } - - // parsing MOS header - uint32_t inOfs = 0; - if (std::memcmp(mosData.get()+inOfs, HEADER_MOS_SIGNATURE, 4) != 0) { - std::printf("Invalid MOS signature\n"); - return false; - } - inOfs += 4; - - if (std::memcmp(mosData.get()+inOfs, HEADER_VERSION_V1, 4) != 0) { - std::printf("Unsupported MOS version\n"); - return false; - } - inOfs += 4; - - std::memcpy(&mosWidth, mosData.get()+inOfs, 2); - mosWidth = get16u_le(&mosWidth); - if (mosWidth == 0) { - std::printf("Invalid MOS width\n"); - return false; - } - inOfs += 2; - - mosHeight = get16u_le((uint16_t*)(mosData.get()+inOfs)); - if (mosHeight == 0) { - std::printf("Invalid MOS height\n"); - return false; - } - inOfs += 2; - - mosCols = get16u_le((uint16_t*)(mosData.get()+inOfs)); - if (mosCols == 0) { - std::printf("Invalid number of tiles\n"); - return false; - } - inOfs += 2; - - mosRows = get16u_le((uint16_t*)(mosData.get()+inOfs)); - if (mosRows == 0) { - std::printf("Invalid number of tiles\n"); - return false; - } - inOfs += 2; - - tileDim = get32u_le((uint32_t*)(mosData.get()+inOfs)); - if (tileDim != 0x40) { - std::printf("Invalid tile dimensions\n"); - return false; - } - inOfs += 4; - - palOfs = get32u_le((uint32_t*)(mosData.get()+inOfs)); - if (palOfs < 24) { - std::printf("MOS header too small\n"); - return false; - } - inOfs = palOfs; - - { - // comparing calculated size with actual input file length - uint32_t size = palOfs + mosCols*mosRows*PALETTE_SIZE + mosCols*mosRows*4 + mosWidth*mosHeight; - if (mosSize < size) { - std::printf("Incomplete or corrupted MOS file\n"); - return false; - } - } + // loading MOS/MOSC input data + if (!readMOS(fin, mosData, mosWidth, mosHeight, palOfs)) return false; + mosCols = (mosWidth+63) >> 6; + mosRows = (mosHeight+63) >> 6; File fout(outFile.c_str(), "wb"); fout.setDeleteOnClose(true); @@ -546,52 +306,27 @@ bool Graphics::mosToMBC(const std::string &inFile, const std::string &outFile) n if (fout.write(&v32, 4, 1) != 1) return false; // writing MOS width v32 = mosHeight; v32 = get32u_le(&v32); if (fout.write(&v32, 4, 1) != 1) return false; // writing MOS height + if (getOptions().isVerbose()) std::printf("Tile count: %d\n", tileCount); if (getOptions().getVerbosity() == 1) std::printf("Converting"); // processing tiles - ThreadPoolPtr pool = createThreadPool(*this, getOptions().getThreads(), 64); - unsigned nextTileIdx = 0, curProgress = 0; + ThreadPoolPtr pool = createThreadPool(getOptions().getThreads(), MAX_POOL_TILES); double ratioCount = 0.0; // counts the compression ratios of all tiles - int curIndex = 0; - uint32_t remTileHeight = mosHeight; // remaining tile height to cover - for (uint32_t row = 0; row < mosRows; row++, remTileHeight -= tileDim) { - uint32_t tileHeight = std::min(tileDim, remTileHeight); - uint32_t remTileWidth = mosWidth; // remaining tile width to cover - for (uint32_t col = 0; col < mosCols; col++, curIndex++, remTileWidth -= tileDim) { - uint32_t tileWidth = std::min(tileDim, remTileWidth); - uint32_t tileSizeIndexed = tileWidth*tileHeight; - - if (getOptions().isVerbose()) std::printf("Converting tile #%d\n", curIndex); - - // writing converted tiles to disk - while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { - TileDataPtr retVal = pool->getResult(); - if (retVal == nullptr || retVal->isError()) { - if (retVal != nullptr && !retVal->getErrorMsg().empty()) { - std::printf("\n%s", retVal->getErrorMsg().c_str()); - } - return false; - } - double ratio = 0.0; - if (!writeEncodedTile(retVal, fout, ratio)) { - return false; - } - if (getOptions().getVerbosity() == 1) { - curProgress = showProgress(nextTileIdx, tileCount, curProgress, MAX_PROGRESS, '.'); - } - ratioCount += ratio; - nextTileIdx++; - } - - // creating new tile data object + unsigned tileIdx = 0, nextTileIdx = 0, curProgress = 0; + while (tileIdx < tileCount || !pool->finished()) { + // creating new tile data object + if (tileIdx < tileCount) { + int row = tileIdx / mosCols; + int col = tileIdx % mosCols; + int tileWidth = std::min(TILE_DIMENSION, mosWidth - col*TILE_DIMENSION); + int tileHeight = std::min(TILE_DIMENSION, mosHeight - row*TILE_DIMENSION); BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); BytePtr ptrDeflated(new uint8_t[MAX_TILE_SIZE_32*2], std::default_delete()); TileDataPtr tileData(new TileData(getOptions())); tileData->setEncoding(true); - tileData->setIndex(curIndex); + tileData->setIndex(tileIdx); tileData->setType(Options::GetEncodingCode(getOptions().getEncoding(), getOptions().isDeflate())); tileData->setPaletteData(ptrPalette); tileData->setIndexedData(ptrIndexed); @@ -602,16 +337,14 @@ bool Graphics::mosToMBC(const std::string &inFile, const std::string &outFile) n std::memcpy(tileData->getPaletteData().get(), mosData.get()+palOfs, PALETTE_SIZE); palOfs += PALETTE_SIZE; // reading tile data - std::memcpy(&v32, mosData.get()+tileOfs, 4); - v32 = get32u_le(&v32); + v32 = get32u_le((uint32_t*)(mosData.get()+tileOfs)); tileOfs += 4; - std::memcpy(tileData->getIndexedData().get(), mosData.get()+dataOfs+v32, tileSizeIndexed); + std::memcpy(tileData->getIndexedData().get(), mosData.get()+dataOfs+v32, tileWidth*tileHeight); pool->addTileData(tileData); + tileIdx++; } - } - // retrieving the remaining tile data blocks in queue - while (!pool->finished()) { + // writing converted tiles to disk while (pool->hasResult() && pool->peekResult() != nullptr && (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { TileDataPtr retVal = pool->getResult(); @@ -631,7 +364,9 @@ bool Graphics::mosToMBC(const std::string &inFile, const std::string &outFile) n ratioCount += ratio; nextTileIdx++; } - pool->waitForResult(); + if (tileIdx >= tileCount) { + pool->waitForResult(); + } } if (getOptions().getVerbosity() == 1) std::printf("\n"); @@ -662,38 +397,10 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n if (!inFile.empty() && !outFile.empty() && inFile != outFile) { File fin(inFile.c_str(), "rb"); if (!fin.error()) { - char sig[4], ver[4]; - uint32_t compType, mosWidth, mosHeight; + unsigned compType, mosWidth, mosHeight; // parsing TBC header - if (fin.read(sig, 1, 4) != 4) return false;; - if (std::strncmp(sig, HEADER_MBC_SIGNATURE, 4) != 0) { - std::printf("Invalid MBC signature\n"); - return false; - } - - if (fin.read(ver, 1, 4) != 4) return false; - if (std::strncmp(ver, HEADER_VERSION_V1_0, 4) != 0) { - std::printf("Invalid MBC version\n"); - return false; - } - - if (fin.read(&compType, 4, 1) != 1) return false; - compType = get32u_le(&compType); - - if (fin.read(&mosWidth, 4, 1) != 1) return false; - mosWidth = get32u_le(&mosWidth); - if (mosWidth == 0) { - std::printf("Invalid MBC width\n"); - return false; - } - - if (fin.read(&mosHeight, 4, 1) != 1) return false; - mosHeight = get32u_le(&mosHeight); - if (mosHeight == 0) { - std::printf("Invalid MBC height\n"); - return false; - } + if (!readMBC(fin, compType, mosWidth, mosHeight)) return false; File fout(outFile.c_str(), "wb"); fout.setDeleteOnClose(true); @@ -702,8 +409,8 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n uint32_t v32; // creating a memory mapped copy of the output file - uint32_t mosCols = (mosWidth + 63) / 64; - uint32_t mosRows = (mosHeight + 63) / 64; + uint32_t mosCols = (mosWidth + 63) >> 6; + uint32_t mosRows = (mosHeight + 63) >> 6; uint32_t palOfs = 0x18; // offset to palette data uint32_t tileOfs = palOfs + mosCols*mosRows*PALETTE_SIZE; // offset to tile offset array uint32_t dataOfsBase = tileOfs + mosCols*mosRows*4, dataOfsRel = 0; // abs. and rel. offsets to data blocks @@ -711,29 +418,20 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n BytePtr mosData(new uint8_t[mosSize], std::default_delete()); // writing MOS header - uint32_t headerOfs = 0; - std::memcpy(mosData.get()+headerOfs, HEADER_MOS_SIGNATURE, 4); - headerOfs += 4; - std::memcpy(mosData.get()+headerOfs, HEADER_VERSION_V1, 4); - headerOfs += 4; - v16 = mosWidth; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos width - headerOfs += 2; - v16 = mosHeight; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos height - headerOfs += 2; - v16 = mosCols; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos columns - headerOfs += 2; - v16 = mosRows; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos rows - headerOfs += 2; - v32 = 0x40; v32 = get32u_le(&v32); - std::memcpy(mosData.get()+headerOfs, &v32, 4); // writing tile dimension - headerOfs += 4; - v32 = 0x18; v32 = get32u_le(&v32); - std::memcpy(mosData.get()+headerOfs, &v32, 4); // writing offset to palettes - headerOfs += 4; + std::memcpy(mosData.get(), HEADER_MOS_SIGNATURE, 4); + std::memcpy(mosData.get()+4, HEADER_VERSION_V1, 4); + v16 = mosWidth; + *(uint16_t*)(mosData.get()+8) = get16u_le(&v16); // writing mos width + v16 = mosHeight; + *(uint16_t*)(mosData.get()+10) = get16u_le(&v16); // writing mos height + v16 = mosCols; + *(uint16_t*)(mosData.get()+12) = get16u_le(&v16); // writing mos columns + v16 = mosRows; + *(uint16_t*)(mosData.get()+14) = get16u_le(&v16); // writing mos rows + v32 = 0x40; + *(uint32_t*)(mosData.get()+16) = get32u_le(&v32); // writing tile dimension + v32 = 0x18; + *(uint32_t*)(mosData.get()+20) = get32u_le(&v32); // writing offset to palettes if (getOptions().isVerbose()) { std::printf("Width: %d, height: %d, columns: %d, rows: %d, encoding: %d - %s\n", @@ -741,39 +439,18 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n } if (getOptions().getVerbosity() == 1) std::printf("Converting"); - ThreadPoolPtr pool = createThreadPool(*this, getOptions().getThreads(), 64); + // processing tiles + ThreadPoolPtr pool = createThreadPool(getOptions().getThreads(), MAX_POOL_TILES); uint32_t tileCount = mosCols * mosRows; - uint32_t nextTileIdx = 0, curProgress = 0; - int curIndex = 0; // the current tile index - for (uint32_t row = 0; row < mosRows; row++) { - for (uint32_t col = 0; col < mosCols; col++, curIndex++) { - if (getOptions().isVerbose()) std::printf("Decoding tile #%d\n", curIndex); - - // writing converted tiles to disk - while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { - TileDataPtr retVal = pool->getResult(); - if (retVal == nullptr || retVal->isError()) { - if (retVal != nullptr && !retVal->getErrorMsg().empty()) { - std::printf("\n%s", retVal->getErrorMsg().c_str()); - } - return false; - } - if (!writeDecodedMosTile(retVal, mosData, palOfs, tileOfs, dataOfsRel, dataOfsBase)) { - return false; - } - if (getOptions().getVerbosity() == 1) { - curProgress = showProgress(nextTileIdx, tileCount, curProgress, MAX_PROGRESS, '.'); - } - nextTileIdx++; - } - - // creating new tile data object - uint32_t chunkSize; + uint32_t tileIdx = 0, nextTileIdx = 0, curProgress = 0; + while (tileIdx < tileCount || !pool->finished()) { + // creating new tile data object + if (tileIdx < tileCount) { + unsigned chunkSize; if (fin.read(&v32, 4, 1) != 1) return false; chunkSize = get32u_le(&v32); if (chunkSize == 0) { - std::printf("\nInvalid block size found for tile #%d\n", curIndex); + std::printf("\nInvalid block size found for tile #%d\n", tileIdx); return false; } BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); @@ -782,18 +459,17 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n if (fin.read(ptrDeflated.get(), 1, chunkSize) != chunkSize) return false; TileDataPtr tileData(new TileData(getOptions())); tileData->setEncoding(false); - tileData->setIndex(curIndex); + tileData->setIndex(tileIdx); tileData->setType(compType); tileData->setPaletteData(ptrPalette); tileData->setIndexedData(ptrIndexed); tileData->setDeflatedData(ptrDeflated); tileData->setSize(chunkSize); pool->addTileData(tileData); + tileIdx++; } - } - // retrieving the remaining tile data blocks in queue - while (!pool->finished()) { + // writing converted tiles to disk while (pool->hasResult() && pool->peekResult() != nullptr && (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { TileDataPtr retVal = pool->getResult(); @@ -811,7 +487,9 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n } nextTileIdx++; } - pool->waitForResult(); + if (tileIdx >= tileCount) { + pool->waitForResult(); + } } if (getOptions().getVerbosity() == 1) std::printf("\n"); @@ -820,28 +498,8 @@ bool Graphics::mbcToMOS(const std::string &inFile, const std::string &outFile) n return false; } - if (getOptions().isMosc()) { - // compressing mos -> mosc - uint32_t moscSize = mosSize*2; - Compression compression; - BytePtr moscData(new uint8_t[moscSize], std::default_delete()); - - // writing MOSC header - std::memcpy(moscData.get(), HEADER_MOSC_SIGNATURE, 4); - std::memcpy(moscData.get()+4, HEADER_VERSION_V1, 4); - v32 = get32u_le(&mosSize); - std::memcpy(moscData.get()+8, &v32, 4); - - // compressing data - uint32_t size = compression.deflate(mosData.get(), mosSize, moscData.get()+12, moscSize-12); - moscSize = size + 12; - - // writing cmos data to file - if (fout.write(moscData.get(), 1, moscSize) != moscSize) return false; - } else { - // writing mos data to file - if (fout.write(mosData.get(), 1, mosSize) != mosSize) return false; - } + // writing MOS/MOSC to disk + if (!writeMos(fout, mosData, mosSize)) return false; // displaying summary if (!getOptions().isSilent()) { @@ -864,27 +522,11 @@ bool Graphics::tizToTIS(const std::string &inFile, const std::string &outFile) n if (!inFile.empty() && !outFile.empty() && inFile != outFile) { File fin(inFile.c_str(), "rb"); if (!fin.error()) { - char sig[4], tsig[4]; - uint32_t compType = Options::GetEncodingCode(Encoding::Z, false); - uint32_t tileCount; - uint16_t v16; + char tsig[4]; + unsigned compType, tileCount; // parsing TIZ header - if (fin.read(sig, 1, 4) != 4) return false;; - if (std::strncmp(sig, HEADER_TIZ_SIGNATURE, 4) != 0) { - std::printf("Invalid TIZ signature\n"); - return false; - } - - if (fin.read(&v16, 2, 1) != 1) return false; - tileCount = get16u_be(&v16); - if (tileCount == 0) { - std::printf("No tiles found\n"); - return false; - } - - // skipping 2 bytes - if (fin.read(&v16, 2, 1) != 1) return false; + if (!readTIZ(fin, compType, tileCount)) return false; File fout(outFile.c_str(), "wb"); fout.setDeleteOnClose(true); @@ -909,63 +551,46 @@ bool Graphics::tizToTIS(const std::string &inFile, const std::string &outFile) n } if (getOptions().getVerbosity() == 1) std::printf("Converting"); - ThreadPoolPtr pool = createThreadPool(*this, getOptions().getThreads(), 64); - uint32_t nextTileIdx = 0, curProgress = 0; - for (uint32_t tileIdx = 0; tileIdx < tileCount; tileIdx++) { - // writing converted tiles to disk - while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { - TileDataPtr retVal = pool->getResult(); - if (retVal == nullptr || retVal->isError()) { - if (retVal != nullptr && !retVal->getErrorMsg().empty()) { - std::printf("\n%s", retVal->getErrorMsg().c_str()); - } - return false; - } - if (!writeDecodedTisTile(retVal, fout)) { + // processing tiles + ThreadPoolPtr pool = createThreadPool(getOptions().getThreads(), MAX_POOL_TILES); + unsigned tileIdx = 0, nextTileIdx = 0, curProgress = 0; + while (tileIdx < tileCount || !pool->finished()) { + if (tileIdx < tileCount) { + // creating new tile data object + uint32_t chunkSize; + BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); + BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); + BytePtr ptrDeflated; + + if (fin.read(tsig, 1, 4) != 4) return false; + if (std::strncmp(tsig, HEADER_TIL0_SIGNATURE, 4) == 0 || + std::strncmp(tsig, HEADER_TIL1_SIGNATURE, 4) == 0 || + std::strncmp(tsig, HEADER_TIL2_SIGNATURE, 4) == 0) { + uint16_t tileSize; + if (fin.read(&tileSize, 2, 1) != 1) return false; + chunkSize = get16u_be(&tileSize); + ptrDeflated.reset(new uint8_t[chunkSize+6], std::default_delete()); + std::memcpy(ptrDeflated.get(), tsig, 4); + std::memcpy(ptrDeflated.get()+4, &tileSize, 2); + if (fin.read(ptrDeflated.get()+6, 1, chunkSize) != chunkSize) return false; + chunkSize += 6; + } else { + std::printf("\nInvalid header found in tile #%d\n", tileIdx); return false; } - if (getOptions().getVerbosity() == 1) { - curProgress = showProgress(nextTileIdx, tileCount, curProgress, MAX_PROGRESS, '.'); - } - nextTileIdx++; - } - - // creating new tile data object - uint32_t chunkSize; - BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); - BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); - BytePtr ptrDeflated; - - if (fin.read(tsig, 1, 4) != 4) return false; - if (std::strncmp(tsig, HEADER_TIL0_SIGNATURE, 4) == 0 || - std::strncmp(tsig, HEADER_TIL1_SIGNATURE, 4) == 0 || - std::strncmp(tsig, HEADER_TIL2_SIGNATURE, 4) == 0) { - uint16_t tileSize; - if (fin.read(&tileSize, 2, 1) != 1) return false; - chunkSize = get16u_be(&tileSize); - ptrDeflated.reset(new uint8_t[chunkSize+6], std::default_delete()); - std::memcpy(ptrDeflated.get(), tsig, 4); - std::memcpy(ptrDeflated.get()+4, &tileSize, 2); - if (fin.read(ptrDeflated.get()+6, 1, chunkSize) != chunkSize) return false; - chunkSize += 6; - } else { - std::printf("\nInvalid header found in tile #%d\n", tileIdx); - return false; + TileDataPtr tileData(new TileData(getOptions())); + tileData->setEncoding(false); + tileData->setIndex(tileIdx); + tileData->setType(compType); + tileData->setPaletteData(ptrPalette); + tileData->setIndexedData(ptrIndexed); + tileData->setDeflatedData(ptrDeflated); + tileData->setSize(chunkSize); + pool->addTileData(tileData); + tileIdx++; } - TileDataPtr tileData(new TileData(getOptions())); - tileData->setEncoding(false); - tileData->setIndex(tileIdx); - tileData->setType(compType); - tileData->setPaletteData(ptrPalette); - tileData->setIndexedData(ptrIndexed); - tileData->setDeflatedData(ptrDeflated); - tileData->setSize(chunkSize); - pool->addTileData(tileData); - } - // retrieving the remaining tile data blocks in queue - while (!pool->finished()) { + // writing converted tiles to disk while (pool->hasResult() && pool->peekResult() != nullptr && (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { TileDataPtr retVal = pool->getResult(); @@ -983,7 +608,9 @@ bool Graphics::tizToTIS(const std::string &inFile, const std::string &outFile) n } nextTileIdx++; } - pool->waitForResult(); + if (tileIdx >= tileCount) { + pool->waitForResult(); + } } if (getOptions().getVerbosity() == 1) std::printf("\n"); @@ -1013,31 +640,11 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n if (!inFile.empty() && !outFile.empty() && inFile != outFile) { File fin(inFile.c_str(), "rb"); if (!fin.error()) { - char sig[4], tsig[4]; - uint32_t compType = Options::GetEncodingCode(Encoding::Z, false); - uint32_t mosWidth, mosHeight; - uint16_t v16; + char tsig[4]; + unsigned compType, mosWidth, mosHeight; // parsing TIZ header - if (fin.read(sig, 1, 4) != 4) return false;; - if (std::strncmp(sig, HEADER_MOZ_SIGNATURE, 4) != 0) { - std::printf("Invalid MOZ signature\n"); - return false; - } - - if (fin.read(&v16, 2, 1) != 1) return false; - mosWidth = get16u_be(&v16); - if (mosWidth == 0) { - std::printf("Invalid MOZ width\n"); - return false; - } - - if (fin.read(&v16, 2, 1) != 1) return false; - mosHeight = get16u_be(&v16); - if (mosHeight == 0) { - std::printf("Invalid MOZ height\n"); - return false; - } + if (!readMOZ(fin, compType, mosWidth, mosHeight)) return false; File fout(outFile.c_str(), "wb"); fout.setDeleteOnClose(true); @@ -1046,8 +653,8 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n uint32_t v32; // creating a memory mapped copy of the output file - uint32_t mosCols = (mosWidth + 63) / 64; - uint32_t mosRows = (mosHeight + 63) / 64; + uint32_t mosCols = (mosWidth + 63) >> 6; + uint32_t mosRows = (mosHeight + 63) >> 6; uint32_t palOfs = 0x18; // offset to palette data uint32_t tileOfs = palOfs + mosCols*mosRows*PALETTE_SIZE; // offset to tile offset array uint32_t dataOfsBase = tileOfs + mosCols*mosRows*4, dataOfsRel = 0; // abs. and rel. offsets to data blocks @@ -1055,29 +662,20 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n BytePtr mosData(new uint8_t[mosSize], std::default_delete()); // writing MOS header - uint32_t headerOfs = 0; - std::memcpy(mosData.get()+headerOfs, HEADER_MOS_SIGNATURE, 4); - headerOfs += 4; - std::memcpy(mosData.get()+headerOfs, HEADER_VERSION_V1, 4); - headerOfs += 4; - v16 = mosWidth; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos width - headerOfs += 2; - v16 = mosHeight; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos height - headerOfs += 2; - v16 = mosCols; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos columns - headerOfs += 2; - v16 = mosRows; v16 = get16u_le(&v16); - std::memcpy(mosData.get()+headerOfs, &v16, 2); // writing mos rows - headerOfs += 2; - v32 = 0x40; v32 = get32u_le(&v32); - std::memcpy(mosData.get()+headerOfs, &v32, 4); // writing tile dimension - headerOfs += 4; - v32 = 0x18; v32 = get32u_le(&v32); - std::memcpy(mosData.get()+headerOfs, &v32, 4); // writing offset to palettes - headerOfs += 4; + std::memcpy(mosData.get(), HEADER_MOS_SIGNATURE, 4); + std::memcpy(mosData.get()+4, HEADER_VERSION_V1, 4); + v16 = mosWidth; + *(uint16_t*)(mosData.get()+8) = get16u_le(&v16); // writing mos width + v16 = mosHeight; + *(uint16_t*)(mosData.get()+10) = get16u_le(&v16); // writing mos height + v16 = mosCols; + *(uint16_t*)(mosData.get()+12) = get16u_le(&v16); // writing mos columns + v16 = mosRows; + *(uint16_t*)(mosData.get()+14) = get16u_le(&v16); // writing mos rows + v32 = 0x40; + *(uint32_t*)(mosData.get()+16) = get32u_le(&v32); // writing tile dimension + v32 = 0x18; + *(uint32_t*)(mosData.get()+20) = get32u_le(&v32); // writing offset to palettes if (getOptions().isVerbose()) { std::printf("Width: %d, height: %d, columns: %d, rows: %d, encoding: %d - %s\n", @@ -1085,34 +683,13 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n } if (getOptions().getVerbosity() == 1) std::printf("Converting"); - ThreadPoolPtr pool = createThreadPool(*this, getOptions().getThreads(), 64); + // processing tiles + ThreadPoolPtr pool = createThreadPool(getOptions().getThreads(), MAX_POOL_TILES); uint32_t tileCount = mosCols * mosRows; - uint32_t nextTileIdx = 0, curProgress = 0; - int curIndex = 0; // the current tile index - for (uint32_t row = 0; row < mosRows; row++) { - for (uint32_t col = 0; col < mosCols; col++, curIndex++) { - if (getOptions().isVerbose()) std::printf("Decoding tile #%d\n", curIndex); - - // writing converted tiles to disk - while (pool->hasResult() && pool->peekResult() != nullptr && - (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { - TileDataPtr retVal = pool->getResult(); - if (retVal == nullptr || retVal->isError()) { - if (retVal != nullptr && !retVal->getErrorMsg().empty()) { - std::printf("\n%s", retVal->getErrorMsg().c_str()); - } - return false; - } - if (!writeDecodedMosTile(retVal, mosData, palOfs, tileOfs, dataOfsRel, dataOfsBase)) { - return false; - } - if (getOptions().getVerbosity() == 1) { - curProgress = showProgress(nextTileIdx, tileCount, curProgress, MAX_PROGRESS, '.'); - } - nextTileIdx++; - } - - // creating new tile data object + uint32_t tileIdx = 0, nextTileIdx = 0, curProgress = 0; + while (tileIdx < tileCount || !pool->finished()) { + // creating new tile data object + if (tileIdx < tileCount) { uint32_t chunkSize; BytePtr ptrIndexed(new uint8_t[MAX_TILE_SIZE_8], std::default_delete()); BytePtr ptrPalette(new uint8_t[PALETTE_SIZE], std::default_delete()); @@ -1130,23 +707,22 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n if (fin.read(ptrDeflated.get()+6, 1, chunkSize) != chunkSize) return false; chunkSize += 6; } else { - std::printf("\nInvalid header found in tile #%d\n", curIndex); + std::printf("\nInvalid header found in tile #%d\n", tileIdx); return false; } TileDataPtr tileData(new TileData(getOptions())); tileData->setEncoding(false); - tileData->setIndex(curIndex); + tileData->setIndex(tileIdx); tileData->setType(compType); tileData->setPaletteData(ptrPalette); tileData->setIndexedData(ptrIndexed); tileData->setDeflatedData(ptrDeflated); tileData->setSize(chunkSize); pool->addTileData(tileData); + tileIdx++; } - } - // retrieving the remaining tile data blocks in queue - while (!pool->finished()) { + // writing converted tiles to disk while (pool->hasResult() && pool->peekResult() != nullptr && (unsigned)pool->peekResult()->getIndex() == nextTileIdx) { TileDataPtr retVal = pool->getResult(); @@ -1164,7 +740,9 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n } nextTileIdx++; } - pool->waitForResult(); + if (tileIdx >= tileCount) { + pool->waitForResult(); + } } if (getOptions().getVerbosity() == 1) std::printf("\n"); @@ -1173,28 +751,8 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n return false; } - if (getOptions().isMosc()) { - // compressing mos -> mosc - uint32_t moscSize = mosSize*2; - Compression compression; - BytePtr moscData(new uint8_t[moscSize], std::default_delete()); - - // writing MOSC header - std::memcpy(moscData.get(), HEADER_MOSC_SIGNATURE, 4); - std::memcpy(moscData.get()+4, HEADER_VERSION_V1, 4); - v32 = get32u_le(&mosSize); - std::memcpy(moscData.get()+8, &v32, 4); - - // compressing data - uint32_t size = compression.deflate(mosData.get(), mosSize, moscData.get()+12, moscSize-12); - moscSize = size + 12; - - // writing cmos data to file - if (fout.write(moscData.get(), 1, moscSize) != moscSize) return false; - } else { - // writing mos data to file - if (fout.write(mosData.get(), 1, mosSize) != mosSize) return false; - } + // writing MOS/MOSC to disk + if (!writeMos(fout, mosData, mosSize)) return false; // displaying summary if (!getOptions().isSilent()) { @@ -1212,6 +770,371 @@ bool Graphics::mozToMOS(const std::string &inFile, const std::string &outFile) n } +bool Graphics::readTIS(File &fin, unsigned &numTiles) noexcept +{ + char id[4]; + bool isHeaderless = false; + uint32_t v32; + + if (fin.read(id, 1, 4) != 4) return false; + if (std::strncmp(id, HEADER_TIS_SIGNATURE, 4) != 0) { + if (getOptions().assumeTis()) { + isHeaderless = true; + } else { + std::printf("Invalid TIS signature\n"); + return false; + } + } + + if (!isHeaderless) { + if (fin.read(id, 1, 4) != 4) return false; + if (std::strncmp(id, HEADER_VERSION_V2, 4) == 0) { + if (!getOptions().isSilent()) { + std::printf("Warning: Incorrect TIS version 2 found. Converting anyway.\n"); + } + } else if (std::strncmp(id, HEADER_VERSION_V1, 4) != 0) { + std::printf("Invalid TIS version\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + numTiles = get32u_le(&v32); + if (numTiles == 0) { + std::printf("No tiles found\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + v32 = get32u_le(&v32); + if (v32 != 0x1400) { + if (v32 == 0x000c) { + std::printf("PVRZ-based TIS files are not supported\n"); + } else { + std::printf("Invalid tile size\n"); + } + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + v32 = get32u_le(&v32); + if (v32 < 0x18) { + std::printf("Invalid header size\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + v32 = get32u_le(&v32); + if (v32 != 0x40) { + std::printf("Invalid tile dimensions\n"); + return false; + } + } else { + long size = fin.getsize(); + fin.seek(0L, SEEK_SET); + if (size < 0L) { + std::printf("Error reading input file\n"); + return false; + } else if ((size % 5120) != 0) { + std::printf("Headerless TIS has wrong file size\n"); + return false; + } else { + if (!getOptions().isSilent()) std::printf("Warning: Headerless TIS file detected\n"); + numTiles = (unsigned)size / 0x1400; + } + } + + return true; +} + + +bool Graphics::readMOS(File &fin, BytePtr &mos, unsigned &width, unsigned &height, + unsigned &palOfs) noexcept +{ + char id[4]; + uint32_t v32, mosSize; + + // loading MOS/MOSC input file + if (fin.read(id, 1, 4) != 4) return false;; + if (std::strncmp(id, HEADER_MOSC_SIGNATURE, 4) == 0) { // decompressing MOSC + uint32_t moscSize; + Compression compression; + + // getting MOSC file size + moscSize = fin.getsize(); + if (moscSize <= 12) { + std::printf("Invalid MOSC size\n"); + return false; + } + moscSize -= 12; // removing header size + + if (fin.read(&id, 1, 4) != 4) return false; + if (std::strncmp(id, HEADER_VERSION_V1, 4) != 0) { + std::printf("Invalid MOSC version\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + mosSize = get32u_le(&v32); + if (mosSize < 24) { + std::printf("MOS size too small\n"); + return false; + } + BytePtr moscData(new uint8_t[moscSize], std::default_delete()); + if (fin.read(moscData.get(), 1, moscSize) < moscSize) { + std::printf("Incomplete or corrupted MOSC file\n"); + return false; + } + + mos.reset(new uint8_t[mosSize], std::default_delete()); + unsigned size = compression.inflate(moscData.get(), moscSize, mos.get(), mosSize); + if (size != mosSize) { + std::printf("Error while decompressing MOSC input file\n"); + return false; + } + } else if (std::strncmp(id, HEADER_MOS_SIGNATURE, 4) == 0) { // loading MOS data + mosSize = fin.getsize(); + if (mosSize < 24) { + std::printf("MOS size too small\n"); + return false; + } + fin.seek(0, SEEK_SET); + mos.reset(new uint8_t[mosSize], std::default_delete()); + if (fin.read(mos.get(), 1, mosSize) != mosSize) return false; + } else { + std::printf("Invalid MOS signature\n"); + return false; + } + + // parsing MOS header + uint32_t inOfs = 0; + if (std::memcmp(mos.get()+inOfs, HEADER_MOS_SIGNATURE, 4) != 0) { + std::printf("Invalid MOS signature\n"); + return false; + } + inOfs += 4; + + if (std::memcmp(mos.get()+inOfs, HEADER_VERSION_V1, 4) != 0) { + std::printf("Unsupported MOS version\n"); + return false; + } + inOfs += 4; + + width = get16u_le((uint16_t*)(mos.get()+inOfs)); + if (width == 0) { + std::printf("Invalid MOS width\n"); + return false; + } + inOfs += 2; + + height = get16u_le((uint16_t*)(mos.get()+inOfs)); + if (height == 0) { + std::printf("Invalid MOS height\n"); + return false; + } + inOfs += 2; + + if (get16u_le((uint16_t*)(mos.get()+inOfs)) == 0) { + std::printf("Invalid number of tiles\n"); + return false; + } + inOfs += 2; + + if (get16u_le((uint16_t*)(mos.get()+inOfs)) == 0) { + std::printf("Invalid number of tiles\n"); + return false; + } + inOfs += 2; + + if (get32u_le((uint32_t*)(mos.get()+inOfs)) != 0x40) { + std::printf("Invalid tile dimensions\n"); + return false; + } + inOfs += 4; + + palOfs = get32u_le((uint32_t*)(mos.get()+inOfs)); + if (palOfs < 24) { + std::printf("MOS header too small\n"); + return false; + } + inOfs = palOfs; + + { + unsigned cols = (width+63) >> 6; + unsigned rows = (height+63) >> 6; + // comparing calculated size with actual input file length + uint32_t size = palOfs + cols*rows*PALETTE_SIZE + cols*rows*4 + width*height; + if (mosSize < size) { + std::printf("Incomplete or corrupted MOS file\n"); + return false; + } + } + + return true; +} + + +bool Graphics::readTBC(File &fin, unsigned &type, unsigned &numTiles) noexcept +{ + char id[4]; + uint32_t v32; + + // parsing TBC header + if (fin.read(id, 1, 4) != 4) return false;; + if (std::strncmp(id, HEADER_TBC_SIGNATURE, 4) != 0) { + std::printf("Invalid TBC signature\n"); + return false; + } + + if (fin.read(id, 1, 4) != 4) return false; + if (std::strncmp(id, HEADER_VERSION_V1_0, 4) != 0) { + std::printf("Unsupported TBC version\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + type = get32u_le(&v32); + + if (fin.read(&v32, 4, 1) != 1) return false; + numTiles = get32u_le(&v32); + if (numTiles == 0) { + std::printf("No tiles found\n"); + return false; + } + + return true; +} + + +bool Graphics::readMBC(File &fin, unsigned &type, unsigned &width, unsigned &height) noexcept +{ + char id[4]; + uint32_t v32; + + // parsing TBC header + if (fin.read(id, 1, 4) != 4) return false;; + if (std::strncmp(id, HEADER_MBC_SIGNATURE, 4) != 0) { + std::printf("Invalid MBC signature\n"); + return false; + } + + if (fin.read(id, 1, 4) != 4) return false; + if (std::strncmp(id, HEADER_VERSION_V1_0, 4) != 0) { + std::printf("Invalid MBC version\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + type = get32u_le(&v32); + + if (fin.read(&v32, 4, 1) != 1) return false; + width = get32u_le(&v32); + if (width == 0) { + std::printf("Invalid MBC width\n"); + return false; + } + + if (fin.read(&v32, 4, 1) != 1) return false; + height = get32u_le(&v32); + if (height == 0) { + std::printf("Invalid MBC height\n"); + return false; + } + + return true; +} + + +bool Graphics::readTIZ(File &fin, unsigned &type, unsigned &numTiles) noexcept +{ + char id[4]; + uint16_t v16; + + type = Options::GetEncodingCode(Encoding::Z, false); + + // parsing TIZ header + if (fin.read(id, 1, 4) != 4) return false;; + if (std::strncmp(id, HEADER_TIZ_SIGNATURE, 4) != 0) { + std::printf("Invalid TIZ signature\n"); + return false; + } + + if (fin.read(&v16, 2, 1) != 1) return false; + numTiles = get16u_be(&v16); + if (numTiles == 0) { + std::printf("No tiles found\n"); + return false; + } + + // skipping 2 bytes + if (fin.read(&v16, 2, 1) != 1) return false; + + return true; +} + + +bool Graphics::readMOZ(File &fin, unsigned &type, unsigned &width, unsigned &height) noexcept +{ + char id[4]; + uint16_t v16; + + type = Options::GetEncodingCode(Encoding::Z, false); + + // parsing TIZ header + if (fin.read(id, 1, 4) != 4) return false;; + if (std::strncmp(id, HEADER_MOZ_SIGNATURE, 4) != 0) { + std::printf("Invalid MOZ signature\n"); + return false; + } + + if (fin.read(&v16, 2, 1) != 1) return false; + width = get16u_be(&v16); + if (width == 0) { + std::printf("Invalid MOZ width\n"); + return false; + } + + if (fin.read(&v16, 2, 1) != 1) return false; + height = get16u_be(&v16); + if (height == 0) { + std::printf("Invalid MOZ height\n"); + return false; + } + + return true; +} + + +bool Graphics::writeMos(File &fout, BytePtr &mos, unsigned size) noexcept +{ + if (mos != nullptr && size > 0) { + if (getOptions().isMosc()) { + // compressing mos -> mosc + uint32_t moscSize = size*2; + uint32_t v32; + Compression compression; + BytePtr moscData(new uint8_t[moscSize], std::default_delete()); + + // writing MOSC header + std::memcpy(moscData.get(), HEADER_MOSC_SIGNATURE, 4); + std::memcpy(moscData.get()+4, HEADER_VERSION_V1, 4); + v32 = size; + *(uint32_t*)(moscData.get()+8) = get32u_le(&v32); + + // compressing data + moscSize = compression.deflate(mos.get(), size, moscData.get()+12, moscSize-12); + moscSize += 12; + + // writing cmos data to file + if (fout.write(moscData.get(), 1, moscSize) == moscSize) return true; + } else { + // writing mos data to file + if (fout.write(mos.get(), 1, size) == size) return true; + } + } + return false; +} + + bool Graphics::writeEncodedTile(TileDataPtr tileData, File &file, double &ratio) noexcept { if (tileData != nullptr) { diff --git a/tileconv/graphics.h b/tileconv/graphics.h index 5140c66..e7cd48b 100644 --- a/tileconv/graphics.h +++ b/tileconv/graphics.h @@ -54,6 +54,22 @@ class Graphics const Options& getOptions() const noexcept { return m_options; } private: + // Read TIS header data. File points to start of tile data afterwards. + bool readTIS(File &fin, unsigned &numTiles) noexcept; + // Reads MOS file. mos contains uncompressed MOS data. + bool readMOS(File &fin, BytePtr &mos, unsigned &width, unsigned &height, unsigned &palOfs) noexcept; + // Reads TBC header data. File points to start of tile data afterwards. + bool readTBC(File &fin, unsigned &type, unsigned &numTiles) noexcept; + // Reads MBC header data. File points to start of tile data afterwards. + bool readMBC(File &fin, unsigned &type, unsigned &width, unsigned &height) noexcept; + // Reads TIZ header data. File points to start of tile data afterwards. + bool readTIZ(File &fin, unsigned &type, unsigned &numTiles) noexcept; + // Reads MOZ header data. File points to start of tile data afterwards. + bool readMOZ(File &fin, unsigned &type, unsigned &width, unsigned &height) noexcept; + + // write data as MOS or MOSC to disk + bool writeMos(File &fout, BytePtr &mos, unsigned size) noexcept; + // Called by tisToTBC() and mosToMBC() to write an encoded tile to the output file bool writeEncodedTile(TileDataPtr tileData, File &file, double &ratio) noexcept; @@ -88,6 +104,7 @@ class Graphics private: static const unsigned MAX_PROGRESS; // Available space for a progress bar + static const unsigned MAX_POOL_TILES; // Max. storage of tiles in thread pool const Options& m_options; }; diff --git a/tileconv/options.cpp b/tileconv/options.cpp index c5af26f..6530b99 100644 --- a/tileconv/options.cpp +++ b/tileconv/options.cpp @@ -166,7 +166,7 @@ bool Options::init(int argc, char *argv[]) noexcept setShowInfo(true); break; case 'V': - std::printf("%s %d.%d by %s\n", prog_name, vers_major, vers_minor, author); + std::printf("%s %d.%d.%d by %s\n", prog_name, vers_major, vers_minor, vers_patch, author); return false; default: std::printf("Unrecognized parameter \"-%c\"\n", optopt); diff --git a/tileconv/tileconv.h b/tileconv/tileconv.h index fad3f14..f084fab 100644 --- a/tileconv/tileconv.h +++ b/tileconv/tileconv.h @@ -26,7 +26,7 @@ THE SOFTWARE. namespace tc { -/** High level class for converting TIS<->TBC and MOS<->MBC. */ +/** High level conversion class. */ class TileConv { public: diff --git a/tileconv/tilethreadpool_base.cpp b/tileconv/tilethreadpool_base.cpp index 2ac8839..c4fa00b 100644 --- a/tileconv/tilethreadpool_base.cpp +++ b/tileconv/tilethreadpool_base.cpp @@ -28,9 +28,8 @@ const unsigned TileThreadPool::MAX_THREADS = 256u; const unsigned TileThreadPool::MAX_TILES = std::numeric_limits::max(); -TileThreadPool::TileThreadPool(Graphics &gfx, unsigned tileNum) noexcept -: m_gfx(gfx) -, m_terminate(false) +TileThreadPool::TileThreadPool(unsigned tileNum) noexcept +: m_terminate(false) , m_maxTiles(MAX_TILES) , m_tiles() , m_results() diff --git a/tileconv/tilethreadpool_base.h b/tileconv/tilethreadpool_base.h index 63b0a33..d936806 100644 --- a/tileconv/tilethreadpool_base.h +++ b/tileconv/tilethreadpool_base.h @@ -23,7 +23,6 @@ THE SOFTWARE. #define _TILETHREADPOOL_BASE_H_ #include #include "tiledata.h" -#include "graphics.h" namespace tc { @@ -42,7 +41,7 @@ unsigned getThreadPoolAutoThreads(); * Dynamically create and return a new thread pool instance encapsulated in a smart pointer. * (Defined together with specialized thread pool classes.) */ -ThreadPoolPtr createThreadPool(Graphics &gfx, int threadNum, int tileNum); +ThreadPoolPtr createThreadPool(int threadNum, int tileNum); class TileThreadPool @@ -54,13 +53,6 @@ class TileThreadPool /** Max. number of allowed tile data blocks to add for processing. */ static const unsigned MAX_TILES; -// static unsigned GetMaxThreads() noexcept; - - /** Detected number of separate threads on the current CPU. */ -// static unsigned GetAutoThreads() noexcept; - -// static unsigned GetMaxTiles() noexcept; - public: virtual ~TileThreadPool() noexcept {} @@ -93,7 +85,7 @@ class TileThreadPool typedef std::queue TileQueue; typedef std::priority_queue, std::greater> ResultQueue; - TileThreadPool(Graphics &gfx, unsigned tileNum) noexcept; + TileThreadPool(unsigned tileNum) noexcept; // Called whenever a thread is about to execute another encoding/decoding function virtual void threadActivated() noexcept = 0; @@ -102,10 +94,6 @@ class TileThreadPool // Returns the number of active threads virtual int getActiveThreads() noexcept = 0; - // Access to associated Graphics instance - Graphics& getGraphics() noexcept { return m_gfx; } - const Graphics& getGraphics() const noexcept { return m_gfx; } - // Access to input queue TileQueue& getTileQueue() noexcept { return m_tiles; } const TileQueue& getTileQueue() const noexcept { return m_tiles; } @@ -120,7 +108,6 @@ class TileThreadPool void setTerminate(bool b) noexcept { m_terminate = b; } private: - Graphics &m_gfx; bool m_terminate; unsigned m_maxTiles; TileQueue m_tiles; diff --git a/tileconv/tilethreadpool_posix.cpp b/tileconv/tilethreadpool_posix.cpp index d483db8..2d71302 100644 --- a/tileconv/tilethreadpool_posix.cpp +++ b/tileconv/tilethreadpool_posix.cpp @@ -20,7 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef USE_WINTHREADS -#include "graphics.h" #include "tilethreadpool_posix.h" namespace tc { @@ -31,14 +30,14 @@ unsigned getThreadPoolAutoThreads() } -ThreadPoolPtr createThreadPool(Graphics &gfx, int threadNum, int tileNum) +ThreadPoolPtr createThreadPool(int threadNum, int tileNum) { - return ThreadPoolPtr(new TileThreadPoolPosix(gfx, threadNum, tileNum)); + return ThreadPoolPtr(new TileThreadPoolPosix(threadNum, tileNum)); } -TileThreadPoolPosix::TileThreadPoolPosix(Graphics &gfx, unsigned threadNum, unsigned tileNum) noexcept -: TileThreadPool(gfx, tileNum) +TileThreadPoolPosix::TileThreadPoolPosix(unsigned threadNum, unsigned tileNum) noexcept +: TileThreadPool(tileNum) , m_activeThreads(0) , m_mainThread(std::this_thread::get_id()) , m_activeMutex() diff --git a/tileconv/tilethreadpool_posix.h b/tileconv/tilethreadpool_posix.h index ce1afe2..173b1d5 100644 --- a/tileconv/tilethreadpool_posix.h +++ b/tileconv/tilethreadpool_posix.h @@ -34,7 +34,7 @@ namespace tc { class TileThreadPoolPosix : public TileThreadPool { public: - TileThreadPoolPosix(Graphics &gfx, unsigned threadNum, unsigned tileNum) noexcept; + TileThreadPoolPosix(unsigned threadNum, unsigned tileNum) noexcept; ~TileThreadPoolPosix() noexcept; /** See TileThreadPool::addTileData() */ diff --git a/tileconv/tilethreadpool_win32.cpp b/tileconv/tilethreadpool_win32.cpp index 2675bb7..a64481e 100644 --- a/tileconv/tilethreadpool_win32.cpp +++ b/tileconv/tilethreadpool_win32.cpp @@ -20,7 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef USE_WINTHREADS -#include "graphics.h" #include "tilethreadpool_win32.h" namespace tc { @@ -33,14 +32,14 @@ unsigned getThreadPoolAutoThreads() } -ThreadPoolPtr createThreadPool(Graphics &gfx, int threadNum, int tileNum) +ThreadPoolPtr createThreadPool(int threadNum, int tileNum) { - return ThreadPoolPtr(new TileThreadPoolWin32(gfx, threadNum, tileNum)); + return ThreadPoolPtr(new TileThreadPoolWin32(threadNum, tileNum)); } -TileThreadPoolWin32::TileThreadPoolWin32(Graphics &gfx, unsigned threadNum, unsigned tileNum) noexcept -: TileThreadPool(gfx, tileNum) +TileThreadPoolWin32::TileThreadPoolWin32(unsigned threadNum, unsigned tileNum) noexcept +: TileThreadPool(tileNum) , m_activeThreads(0) , m_mainThread(::GetCurrentThread()) , m_activeMutex(::CreateMutex(NULL, FALSE, NULL)) diff --git a/tileconv/tilethreadpool_win32.h b/tileconv/tilethreadpool_win32.h index 3386546..6e2b080 100644 --- a/tileconv/tilethreadpool_win32.h +++ b/tileconv/tilethreadpool_win32.h @@ -31,7 +31,7 @@ namespace tc { class TileThreadPoolWin32 : public TileThreadPool { public: - TileThreadPoolWin32(Graphics &gfx, unsigned threadNum, unsigned tileNum) noexcept; + TileThreadPoolWin32(unsigned threadNum, unsigned tileNum) noexcept; ~TileThreadPoolWin32() noexcept; /** See TileThreadPool::addTileData() */ diff --git a/tileconv/types.h b/tileconv/types.h index 228e01c..6ac88e5 100644 --- a/tileconv/types.h +++ b/tileconv/types.h @@ -66,8 +66,9 @@ static const unsigned HEADER_TILE_ENCODED_SIZE = 4; // header size for static const unsigned HEADER_TILE_COMPRESSED_SIZE = 4; // header size for a zlib compressed tile static const unsigned PALETTE_SIZE = 1024; // palette size in bytes -static const unsigned MAX_TILE_SIZE_8 = 64*64; // max. size (in bytes) of a 8-bit pixels tile -static const unsigned MAX_TILE_SIZE_32 = 64*64*4; // max. size (in bytes) of a 32-bit pixels tile +static const unsigned TILE_DIMENSION = 64; // max. tile dimension +static const unsigned MAX_TILE_SIZE_8 = TILE_DIMENSION*TILE_DIMENSION; // max. size (in bytes) of a 8-bit pixels tile +static const unsigned MAX_TILE_SIZE_32 = TILE_DIMENSION*TILE_DIMENSION*4; // max. size (in bytes) of a 32-bit pixels tile } // namespace tc diff --git a/tileconv/version.cpp b/tileconv/version.cpp index 9157f17..9556123 100644 --- a/tileconv/version.cpp +++ b/tileconv/version.cpp @@ -21,5 +21,6 @@ THE SOFTWARE. */ int vers_major = 0; int vers_minor = 5; +int vers_patch = 1; char prog_name[] = "tileconv"; char author[] = "Argent77"; diff --git a/tileconv/version.h b/tileconv/version.h index e6ca26a..fa1341b 100644 --- a/tileconv/version.h +++ b/tileconv/version.h @@ -21,5 +21,6 @@ THE SOFTWARE. */ extern int vers_major; extern int vers_minor; +extern int vers_patch; extern char prog_name[]; extern char author[];