/
dieoska
/
ddnet
Обзор
Документация
Войти
/
dieoska
/
ddnet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/tools/map_optimize.cpp
328 строк
8 KB
Robert Müller
Remove most clang-tidy variable/constant/parameter name exclusions
20 окт 2025, 20:37
20 окт 2025, 20:37
c5b3803
Код
Авторство
О чём код?
#include <base/logger.h> #include <base/system.h> #include <engine/gfx/image_manipulation.h> #include <engine/shared/datafile.h> #include <engine/storage.h> #include <game/mapitems.h> #include <algorithm> #include <cstdint> #include <vector> static void ClearTransparentPixels(uint8_t *pImg, int Width, int Height) { for(int y = 0; y < Height; ++y) { for(int x = 0; x < Width; ++x) { int Index = y * Width * 4 + x * 4; if(pImg[Index + 3] == 0) { pImg[Index + 0] = 0; pImg[Index + 1] = 0; pImg[Index + 2] = 0; } } } } static void CopyOpaquePixels(uint8_t *pDestImg, uint8_t *pSrcImg, int Width, int Height) { for(int y = 0; y < Height; ++y) { for(int x = 0; x < Width; ++x) { int Index = y * Width * 4 + x * 4; if(pSrcImg[Index + 3] > 0) mem_copy(&pDestImg[Index], &pSrcImg[Index], sizeof(uint8_t) * 4); else mem_zero(&pDestImg[Index], sizeof(uint8_t) * 4); } } } static void ClearPixelsTile(uint8_t *pImg, int Width, int Height, int TileIndex) { int WTile = Width / 16; int HTile = Height / 16; int StartX = (TileIndex % 16) * WTile; int StartY = (TileIndex / 16) * HTile; for(int y = StartY; y < StartY + HTile; ++y) { for(int x = StartX; x < StartX + WTile; ++x) { int Index = y * Width * 4 + x * 4; pImg[Index + 0] = 0; pImg[Index + 1] = 0; pImg[Index + 2] = 0; pImg[Index + 3] = 0; } } } static void GetImageSHA256(uint8_t *pImgBuff, int ImgSize, int Width, int Height, char *pSHA256Str, size_t SHA256StrSize) { uint8_t *pNewImgBuff = (uint8_t *)malloc(ImgSize); // Clear fully transparent pixels, so the SHA is easier to identify with the original image CopyOpaquePixels(pNewImgBuff, pImgBuff, Width, Height); SHA256_DIGEST SHAStr = sha256(pNewImgBuff, (size_t)ImgSize); sha256_str(SHAStr, pSHA256Str, SHA256StrSize); free(pNewImgBuff); } int main(int argc, const char **argv) { CCmdlineFix CmdlineFix(&argc, &argv); log_set_global_logger_default(); std::unique_ptr<IStorage> pStorage = std::unique_ptr<IStorage>(CreateStorage(IStorage::EInitializationType::BASIC, argc, argv)); if(!pStorage) { log_error("map_optimize", "Error creating basic storage"); return -1; } if(argc <= 1 || argc > 3) { dbg_msg("map_optimize", "Usage: map_optimize <source map filepath> [<dest map filepath>]"); return -1; } char aFilename[IO_MAX_PATH_LENGTH]; if(argc == 3) { str_format(aFilename, sizeof(aFilename), "out/%s", argv[2]); fs_makedir_rec_for(aFilename); } else { fs_makedir("out"); char aBuff[IO_MAX_PATH_LENGTH]; IStorage::StripPathAndExtension(argv[1], aBuff, sizeof(aBuff)); str_format(aFilename, sizeof(aFilename), "out/%s.map", aBuff); } CDataFileReader Reader; if(!Reader.Open(pStorage.get(), argv[1], IStorage::TYPE_ABSOLUTE)) { dbg_msg("map_optimize", "Failed to open source file."); return -1; } CDataFileWriter Writer; if(!Writer.Open(pStorage.get(), aFilename, IStorage::TYPE_ABSOLUTE)) { dbg_msg("map_optimize", "Failed to open target file."); return -1; } int aImageFlags[MAX_MAPIMAGES] = { 0, }; bool aaImageTiles[MAX_MAPIMAGES][256]{ { false, }, }; struct SMapOptimizeItem { CMapItemImage *m_pImage; int m_Index; int m_Data; int m_Text; }; std::vector<SMapOptimizeItem> vDataFindHelper; // add all items for(int Index = 0, i = 0; Index < Reader.NumItems(); Index++) { int Type, Id; CUuid Uuid; void *pPtr = Reader.GetItem(Index, &Type, &Id, &Uuid); // Filter ITEMTYPE_EX items, they will be automatically added again. if(Type == ITEMTYPE_EX) { continue; } // for all layers, check if it uses a image and set the corresponding flag if(Type == MAPITEMTYPE_LAYER) { CMapItemLayer *pLayer = (CMapItemLayer *)pPtr; if(pLayer->m_Type == LAYERTYPE_TILES) { CMapItemLayerTilemap *pTLayer = (CMapItemLayerTilemap *)pLayer; if(pTLayer->m_Image >= 0 && pTLayer->m_Image < (int)MAX_MAPIMAGES && pTLayer->m_Flags == 0) { aImageFlags[pTLayer->m_Image] |= 1; // check tiles that are used in this image unsigned int DataSize = Reader.GetDataSize(pTLayer->m_Data); void *pTiles = Reader.GetData(pTLayer->m_Data); if(DataSize >= (size_t)pTLayer->m_Width * pTLayer->m_Height * sizeof(CTile)) { for(int y = 0; y < pTLayer->m_Height; ++y) { for(int x = 0; x < pTLayer->m_Width; ++x) { int TileIndex = ((CTile *)pTiles)[y * pTLayer->m_Width + x].m_Index; if(TileIndex > 0) { aaImageTiles[pTLayer->m_Image][TileIndex] = true; } } } } } } else if(pLayer->m_Type == LAYERTYPE_QUADS) { CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; if(pQLayer->m_Image >= 0 && pQLayer->m_Image < (int)MAX_MAPIMAGES) { aImageFlags[pQLayer->m_Image] |= 2; } } } else if(Type == MAPITEMTYPE_IMAGE) { CMapItemImage_v2 *pImg = (CMapItemImage_v2 *)pPtr; if(!pImg->m_External && pImg->m_Version < 2) { SMapOptimizeItem Item; Item.m_pImage = pImg; Item.m_Index = i; Item.m_Data = pImg->m_ImageData; Item.m_Text = pImg->m_ImageName; vDataFindHelper.push_back(Item); } // found an image ++i; } int Size = Reader.GetItemSize(Index); Writer.AddItem(Type, Id, Size, pPtr, &Uuid); } // add all data for(int Index = 0; Index < Reader.NumData(); Index++) { bool DeletePtr = false; void *pPtr = Reader.GetData(Index); int Size = Reader.GetDataSize(Index); auto MapDataItemIterator = std::find_if(vDataFindHelper.begin(), vDataFindHelper.end(), [Index](const SMapOptimizeItem &Other) -> bool { return Other.m_Data == Index || Other.m_Text == Index; }); if(MapDataItemIterator != vDataFindHelper.end()) { int Width = MapDataItemIterator->m_pImage->m_Width; int Height = MapDataItemIterator->m_pImage->m_Height; int ImageIndex = MapDataItemIterator->m_Index; if(MapDataItemIterator->m_Data == Index) { DeletePtr = true; // optimize embedded images // use a new pointer, to be safe, when using the original image data void *pNewPtr = malloc(Size); mem_copy(pNewPtr, pPtr, Size); pPtr = pNewPtr; uint8_t *pImgBuff = (uint8_t *)pPtr; bool DoClearTransparentPixels = false; bool DilateAs2DArray = false; bool DoDilate = false; // all tiles that aren't used are cleared(if image was only used by tilemap) if(aImageFlags[ImageIndex] == 1) { for(int i = 0; i < 256; ++i) { if(!aaImageTiles[ImageIndex][i]) { ClearPixelsTile(pImgBuff, Width, Height, i); } } DoClearTransparentPixels = true; DilateAs2DArray = true; DoDilate = true; } else if(aImageFlags[ImageIndex] == 0) { mem_zero(pImgBuff, (size_t)Width * Height * 4); } else { DoClearTransparentPixels = true; DoDilate = true; } if(DoClearTransparentPixels) { // clear unused pixels and make a clean dilate for the compressor ClearTransparentPixels(pImgBuff, Width, Height); } if(DoDilate) { if(DilateAs2DArray) { for(int i = 0; i < 256; ++i) { int ImgTileW = Width / 16; int ImgTileH = Height / 16; int x = (i % 16) * ImgTileW; int y = (i / 16) * ImgTileH; DilateImageSub(pImgBuff, Width, Height, x, y, ImgTileW, ImgTileH); } } else { DilateImage(pImgBuff, Width, Height); } } } else if(MapDataItemIterator->m_Text == Index) { char *pImgName = (char *)pPtr; uint8_t *pImgBuff = (uint8_t *)Reader.GetData(MapDataItemIterator->m_Data); int ImgSize = Reader.GetDataSize(MapDataItemIterator->m_Data); char aSHA256Str[SHA256_MAXSTRSIZE]; // This is the important function, that calculates the SHA256 in a special way // Please read the comments inside the functions to understand it GetImageSHA256(pImgBuff, ImgSize, Width, Height, aSHA256Str, sizeof(aSHA256Str)); char aNewName[IO_MAX_PATH_LENGTH]; int StrLen = str_format(aNewName, std::size(aNewName), "%s_cut_%s", pImgName, aSHA256Str); DeletePtr = true; // make the new name ready char *pNewPtr = (char *)malloc(StrLen + 1); str_copy(pNewPtr, aNewName, StrLen + 1); pPtr = pNewPtr; Size = StrLen + 1; } } Writer.AddData(Size, pPtr, CDataFileWriter::COMPRESSION_BEST); if(DeletePtr) free(pPtr); } Reader.Close(); Writer.Finish(); return 0; }