HdImageLoader.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * HdImageLoader.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "HdImageLoader.h"
  12. #include "PakLoader.h"
  13. #include "DdsFormat.h"
  14. #include <SDL_image.h>
  15. #include <unordered_set>
  16. #include "../../GameEngine.h"
  17. #include "../../render/CBitmapHandler.h"
  18. #include "../../render/IScreenHandler.h"
  19. #include "../../renderSDL/SDLImage.h"
  20. #include "../../renderSDL/SDL_Extensions.h"
  21. #include "../../../lib/filesystem/ResourcePath.h"
  22. #include "../../../lib/filesystem/Filesystem.h"
  23. #include "../../../lib/filesystem/CCompressedStream.h"
  24. #include "../../../lib/filesystem/CMemoryStream.h"
  25. const std::unordered_set<std::string> animToSkip = {
  26. // skip menu buttons (RoE)
  27. "MMENUNG", "MMENULG", "MMENUHS", "MMENUCR", "MMENUQT", "GTSINGL", "GTMULTI", "GTCAMPN", "GTTUTOR", "GTBACK", "GTSINGL", "GTMULTI", "GTCAMPN", "GTTUTOR", "GTBACK",
  28. // skip dialogbox - coloring not supported yet
  29. "DIALGBOX",
  30. // skip water + rivers
  31. "WATRTL", "LAVATL", "CLRRVR", "MUDRVR", "LAVRVR"
  32. };
  33. const std::unordered_set<std::string> imagesToSkip = {
  34. // skip RoE specific files
  35. "MAINMENU", "GAMSELBK", "GSELPOP1", "SCSELBCK", "GSSTRIP", "LOADGAME", "NEWGAME", "LOADBAR"
  36. };
  37. const std::unordered_set<std::string> hdColors = {
  38. // skip colored variants - coloring not supported yet
  39. "_RED", "_BLUE", "_SAND", "_GREEN", "_ORANGE", "_PURPLE", "_BLUEWIN", "_FLESH"
  40. };
  41. HdImageLoader::HdImageLoader()
  42. : pakLoader(std::make_shared<PakLoader>())
  43. , ddsFormat(std::make_shared<DdsFormat>())
  44. , scalingFactor(ENGINE->screenHandler().getScalingFactor())
  45. , flagImg({nullptr, nullptr})
  46. {
  47. const std::vector<std::pair<int, ResourcePath>> files = {
  48. {2, ResourcePath("DATA/bitmap_DXT_com_x2.pak", EResType::ARCHIVE_PAK)},
  49. {2, ResourcePath("DATA/bitmap_DXT_loc_x2.pak", EResType::ARCHIVE_PAK)},
  50. {2, ResourcePath("DATA/sprite_DXT_com_x2.pak", EResType::ARCHIVE_PAK)},
  51. {2, ResourcePath("DATA/sprite_DXT_loc_x2.pak", EResType::ARCHIVE_PAK)},
  52. {3, ResourcePath("DATA/bitmap_DXT_com_x3.pak", EResType::ARCHIVE_PAK)},
  53. {3, ResourcePath("DATA/bitmap_DXT_loc_x3.pak", EResType::ARCHIVE_PAK)},
  54. {3, ResourcePath("DATA/sprite_DXT_com_x3.pak", EResType::ARCHIVE_PAK)},
  55. {3, ResourcePath("DATA/sprite_DXT_loc_x3.pak", EResType::ARCHIVE_PAK)}
  56. };
  57. for(auto & file : files)
  58. if(CResourceHandler::get()->existsResource(file.second) && scalingFactor == file.first)
  59. pakLoader->loadPak(file.second, file.first, animToSkip, imagesToSkip, hdColors);
  60. loadFlagData();
  61. }
  62. HdImageLoader::~HdImageLoader()
  63. {
  64. if(flagImg[0])
  65. SDL_FreeSurface(flagImg[0]);
  66. if(flagImg[1])
  67. SDL_FreeSurface(flagImg[1]);
  68. }
  69. void HdImageLoader::loadFlagData()
  70. {
  71. auto res = ResourcePath("DATA/spriteFlagsInfo.txt", EResType::TEXT);
  72. if(!CResourceHandler::get()->existsResource(res))
  73. return;
  74. auto data = CResourceHandler::get()->load(res)->readAll();
  75. std::string s(reinterpret_cast<const char*>(data.first.get()), data.second);
  76. std::istringstream ss(s);
  77. std::string line;
  78. while (std::getline(ss, line))
  79. {
  80. boost::algorithm::trim(line);
  81. if(line.empty())
  82. continue;
  83. std::vector<std::string> tokens;
  84. boost::split(tokens, line, boost::is_space(), boost::token_compress_on);
  85. std::string key = tokens[0];
  86. std::vector<int> values;
  87. for (size_t i = 1; i < tokens.size(); ++i)
  88. values.push_back(std::stoi(tokens[i]));
  89. flagData[key] = values;
  90. }
  91. auto flag = scalingFactor == 3 ? "DATA/flags/flag_grey.png" : "DATA/flags/flag_grey_x2.png";
  92. flagImg[0] = BitmapHandler::loadBitmap(ImagePath::builtin(flag));
  93. CSDL_Ext::adjustBrightness(flagImg[0], 2.5f);
  94. flagImg[1] = CSDL_Ext::verticalFlip(flagImg[0]);
  95. }
  96. std::shared_ptr<SDLImageShared> HdImageLoader::getImage(const ImagePath & path, const Point & fullSize, const Point & margins, bool shadow, bool overlay)
  97. {
  98. auto imageName = path.getName();
  99. auto ret = find(path);
  100. if(!ret)
  101. return nullptr;
  102. if(overlay && !flagData.contains(imageName))
  103. return nullptr;
  104. else if(overlay)
  105. {
  106. auto surf = CSDL_Ext::newSurface(fullSize * scalingFactor);
  107. for(int i = 0; i < flagData[imageName][0]; ++i)
  108. {
  109. bool flagMirror = flagData[imageName][3 + i * 3];
  110. CSDL_Ext::blitSurface(flagMirror ? flagImg[1] : flagImg[0], surf, Point(flagData[imageName][1 + i * 3], flagData[imageName][2 + i * 3]) * scalingFactor);
  111. }
  112. auto img = std::make_shared<SDLImageShared>(surf);
  113. SDL_FreeSurface(surf);
  114. return img;
  115. }
  116. auto [res, entry, image] = *ret;
  117. auto sheetIndex = shadow ? image.shadowSheetIndex : image.sheetIndex;
  118. auto sheetOffsetX = shadow ? image.shadowSheetOffsetX : image.sheetOffsetX;
  119. auto sheetOffsetY = shadow ? image.shadowSheetOffsetY : image.sheetOffsetY;
  120. auto rotation = shadow ? image.shadowRotation : image.rotation;
  121. auto width = shadow ? image.shadowWidth : image.width;
  122. auto height = shadow ? image.shadowHeight : image.height;
  123. std::unique_ptr<CInputStream> file = CResourceHandler::get()->load(res);
  124. file->seek(entry.metadataOffset);
  125. file->skip(entry.metadataSize);
  126. for(size_t i = 0; i < sheetIndex; ++i)
  127. file->skip(entry.sheets[i].compressedSize);
  128. CCompressedStream compressedReader(std::move(file), false, entry.sheets[sheetIndex].fullSize);
  129. Rect sheetRect(sheetOffsetX, sheetOffsetY, width, height);
  130. auto surfCropped = ddsFormat->load(&compressedReader, entry.name + std::to_string(sheetIndex), &sheetRect);
  131. SDL_Surface * surfRotated = rotation ? CSDL_Ext::Rotate90(surfCropped) : nullptr;
  132. auto img = std::make_shared<SDLImageShared>(surfRotated ? surfRotated : surfCropped);
  133. if(fullSize.x > 0 && fullSize.y > 0)
  134. img->setFullSize(fullSize * scalingFactor);
  135. img->setMargins((margins - Point(image.spriteOffsetX, image.spriteOffsetY)) * scalingFactor);
  136. SDL_FreeSurface(surfCropped);
  137. if(surfRotated)
  138. SDL_FreeSurface(surfRotated);
  139. return img;
  140. }
  141. std::optional<std::tuple<ResourcePath, PakLoader::ArchiveEntry, PakLoader::ImageEntry>> HdImageLoader::find(const ImagePath & path)
  142. {
  143. const auto targetName = boost::algorithm::to_upper_copy(path.getName());
  144. int scale = scalingFactor;
  145. auto scaleIt = pakLoader->imagesByName.find(scale);
  146. if (scaleIt != pakLoader->imagesByName.end())
  147. {
  148. auto &nameMap = scaleIt->second;
  149. auto imageIt = nameMap.find(targetName);
  150. if (imageIt != nameMap.end())
  151. {
  152. auto &[resourcePath, imagePtr, entryPtr] = imageIt->second;
  153. return std::make_tuple(resourcePath, *entryPtr, *imagePtr);
  154. }
  155. }
  156. return std::nullopt;
  157. }
  158. bool HdImageLoader::exists(const ImagePath & path)
  159. {
  160. return find(path).has_value();
  161. }