ScalableImage.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /*
  2. * ScalableImage.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 "ScalableImage.h"
  12. #include "SDLImage.h"
  13. #include "SDL_Extensions.h"
  14. #include "../gui/CGuiHandler.h"
  15. #include "../render/ColorFilter.h"
  16. #include "../render/Colors.h"
  17. #include "../render/Graphics.h"
  18. #include "../render/IRenderHandler.h"
  19. #include "../render/IScreenHandler.h"
  20. #include "../render/CanvasImage.h"
  21. #include "../../lib/constants/EntityIdentifiers.h"
  22. #include <SDL_surface.h>
  23. //First 8 colors in def palette used for transparency
  24. static constexpr std::array<SDL_Color, 8> sourcePalette = {{
  25. {0, 255, 255, SDL_ALPHA_OPAQUE},
  26. {255, 150, 255, SDL_ALPHA_OPAQUE},
  27. {255, 100, 255, SDL_ALPHA_OPAQUE},
  28. {255, 50, 255, SDL_ALPHA_OPAQUE},
  29. {255, 0, 255, SDL_ALPHA_OPAQUE},
  30. {255, 255, 0, SDL_ALPHA_OPAQUE},
  31. {180, 0, 255, SDL_ALPHA_OPAQUE},
  32. {0, 255, 0, SDL_ALPHA_OPAQUE}
  33. }};
  34. static constexpr std::array<ColorRGBA, 8> targetPalette = {{
  35. {0, 0, 0, 0 }, // 0 - transparency ( used in most images )
  36. {0, 0, 0, 64 }, // 1 - shadow border ( used in battle, adventure map def's )
  37. {0, 0, 0, 64 }, // 2 - shadow border ( used in fog-of-war def's )
  38. {0, 0, 0, 128}, // 3 - shadow body ( used in fog-of-war def's )
  39. {0, 0, 0, 128}, // 4 - shadow body ( used in battle, adventure map def's )
  40. {0, 0, 0, 0 }, // 5 - selection / owner flag ( used in battle, adventure map def's )
  41. {0, 0, 0, 128}, // 6 - shadow body below selection ( used in battle def's )
  42. {0, 0, 0, 64 } // 7 - shadow border below selection ( used in battle def's )
  43. }};
  44. static ui8 mixChannels(ui8 c1, ui8 c2, ui8 a1, ui8 a2)
  45. {
  46. return c1*a1 / 256 + c2*a2*(255 - a1) / 256 / 256;
  47. }
  48. static ColorRGBA addColors(const ColorRGBA & base, const ColorRGBA & over)
  49. {
  50. return ColorRGBA(
  51. mixChannels(over.r, base.r, over.a, base.a),
  52. mixChannels(over.g, base.g, over.a, base.a),
  53. mixChannels(over.b, base.b, over.a, base.a),
  54. static_cast<ui8>(over.a + base.a * (255 - over.a) / 256)
  55. );
  56. }
  57. static bool colorsSimilar (const SDL_Color & lhs, const SDL_Color & rhs)
  58. {
  59. // it seems that H3 does not requires exact match to replace colors -> (255, 103, 255) gets interpreted as shadow
  60. // exact logic is not clear and requires extensive testing with image editing
  61. // potential reason is that H3 uses 16-bit color format (565 RGB bits), meaning that 3 least significant bits are lost in red and blue component
  62. static const int threshold = 8;
  63. int diffR = static_cast<int>(lhs.r) - rhs.r;
  64. int diffG = static_cast<int>(lhs.g) - rhs.g;
  65. int diffB = static_cast<int>(lhs.b) - rhs.b;
  66. int diffA = static_cast<int>(lhs.a) - rhs.a;
  67. return std::abs(diffR) < threshold && std::abs(diffG) < threshold && std::abs(diffB) < threshold && std::abs(diffA) < threshold;
  68. }
  69. ScalableImageParameters::ScalableImageParameters(const SDL_Palette * originalPalette, EImageBlitMode blitMode)
  70. {
  71. if (originalPalette)
  72. {
  73. palette = SDL_AllocPalette(originalPalette->ncolors);
  74. SDL_SetPaletteColors(palette, originalPalette->colors, 0, originalPalette->ncolors);
  75. preparePalette(originalPalette, blitMode);
  76. }
  77. }
  78. ScalableImageParameters::~ScalableImageParameters()
  79. {
  80. SDL_FreePalette(palette);
  81. }
  82. void ScalableImageParameters::preparePalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode)
  83. {
  84. switch(blitMode)
  85. {
  86. case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
  87. case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
  88. case EImageBlitMode::ONLY_FLAG_COLOR:
  89. case EImageBlitMode::ONLY_SELECTION:
  90. adjustPalette(originalPalette, blitMode, ColorFilter::genAlphaShifter(0), 0);
  91. break;
  92. }
  93. switch(blitMode)
  94. {
  95. case EImageBlitMode::SIMPLE:
  96. case EImageBlitMode::WITH_SHADOW:
  97. case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
  98. case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
  99. case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
  100. case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
  101. setShadowTransparency(originalPalette, 1.0);
  102. break;
  103. case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
  104. case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
  105. case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
  106. case EImageBlitMode::ONLY_FLAG_COLOR:
  107. case EImageBlitMode::ONLY_SELECTION:
  108. setShadowTransparency(originalPalette, 0.0);
  109. break;
  110. }
  111. switch(blitMode)
  112. {
  113. case EImageBlitMode::ONLY_FLAG_COLOR:
  114. case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
  115. setOverlayColor(originalPalette, Colors::WHITE_TRUE, false);
  116. break;
  117. case EImageBlitMode::ONLY_SELECTION:
  118. case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
  119. setOverlayColor(originalPalette, Colors::WHITE_TRUE, true);
  120. break;
  121. case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
  122. case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
  123. setOverlayColor(originalPalette, Colors::TRANSPARENCY, false);
  124. break;
  125. case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
  126. case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
  127. setOverlayColor(originalPalette, Colors::TRANSPARENCY, true);
  128. break;
  129. }
  130. }
  131. void ScalableImageParameters::setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color, bool includeShadow)
  132. {
  133. palette->colors[5] = CSDL_Ext::toSDL(addColors(targetPalette[5], color));
  134. if (includeShadow)
  135. {
  136. for (int i : {6,7})
  137. palette->colors[i] = CSDL_Ext::toSDL(addColors(targetPalette[i], color));
  138. }
  139. }
  140. void ScalableImageParameters::shiftPalette(const SDL_Palette * originalPalette, uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
  141. {
  142. std::vector<SDL_Color> shifterColors(colorsToMove);
  143. for(uint32_t i=0; i<colorsToMove; ++i)
  144. shifterColors[(i+distanceToMove)%colorsToMove] = originalPalette->colors[firstColorID + i];
  145. SDL_SetPaletteColors(palette, shifterColors.data(), firstColorID, colorsToMove);
  146. }
  147. void ScalableImageParameters::setShadowTransparency(const SDL_Palette * originalPalette, float factor)
  148. {
  149. ColorRGBA shadow50(0, 0, 0, 128 * factor);
  150. ColorRGBA shadow25(0, 0, 0, 64 * factor);
  151. std::array<SDL_Color, 5> colorsSDL = {
  152. originalPalette->colors[0],
  153. originalPalette->colors[1],
  154. originalPalette->colors[2],
  155. originalPalette->colors[3],
  156. originalPalette->colors[4]
  157. };
  158. // seems to be used unconditionally
  159. colorsSDL[0] = CSDL_Ext::toSDL(Colors::TRANSPARENCY);
  160. colorsSDL[1] = CSDL_Ext::toSDL(shadow25);
  161. colorsSDL[4] = CSDL_Ext::toSDL(shadow50);
  162. // seems to be used only if color matches
  163. if (colorsSimilar(originalPalette->colors[2], sourcePalette[2]))
  164. colorsSDL[2] = CSDL_Ext::toSDL(shadow25);
  165. if (colorsSimilar(originalPalette->colors[3], sourcePalette[3]))
  166. colorsSDL[3] = CSDL_Ext::toSDL(shadow50);
  167. SDL_SetPaletteColors(palette, colorsSDL.data(), 0, colorsSDL.size());
  168. }
  169. void ScalableImageParameters::adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask)
  170. {
  171. // If shadow is enabled, following colors must be skipped unconditionally
  172. if (blitMode == EImageBlitMode::WITH_SHADOW || blitMode == EImageBlitMode::WITH_SHADOW_AND_SELECTION || blitMode == EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR)
  173. colorsToSkipMask |= (1 << 0) + (1 << 1) + (1 << 4);
  174. // Note: here we skip first colors in the palette that are predefined in H3 images
  175. for(int i = 0; i < palette->ncolors; i++)
  176. {
  177. if (i < std::size(sourcePalette) && colorsSimilar(sourcePalette[i], originalPalette->colors[i]))
  178. continue;
  179. if(i < std::numeric_limits<uint32_t>::digits && ((colorsToSkipMask >> i) & 1) == 1)
  180. continue;
  181. palette->colors[i] = CSDL_Ext::toSDL(shifter.shiftColor(CSDL_Ext::fromSDL(originalPalette->colors[i])));
  182. }
  183. }
  184. ScalableImageShared::ScalableImageShared(const SharedImageLocator & locator, const std::shared_ptr<const ISharedImage> & baseImage)
  185. :locator(locator)
  186. {
  187. scaled[1].body[0] = baseImage;
  188. assert(scaled[1].body[0] != nullptr);
  189. loadScaledImages(GH.screenHandler().getScalingFactor(), PlayerColor::CANNOT_DETERMINE);
  190. }
  191. Point ScalableImageShared::dimensions() const
  192. {
  193. return scaled[1].body[0]->dimensions();
  194. }
  195. void ScalableImageShared::exportBitmap(const boost::filesystem::path & path, const ScalableImageParameters & parameters) const
  196. {
  197. scaled[1].body[0]->exportBitmap(path, parameters.palette);
  198. }
  199. bool ScalableImageShared::isTransparent(const Point & coords) const
  200. {
  201. return scaled[1].body[0]->isTransparent(coords);
  202. }
  203. Rect ScalableImageShared::contentRect() const
  204. {
  205. return scaled[1].body[0]->contentRect();
  206. }
  207. void ScalableImageShared::draw(SDL_Surface * where, const Point & dest, const Rect * src, const ScalableImageParameters & parameters, int scalingFactor)
  208. {
  209. const auto & getFlippedImage = [&](FlippedImages & images){
  210. int index = 0;
  211. if (parameters.flipVertical)
  212. {
  213. if (!images[index|1])
  214. images[index|1] = images[index]->verticalFlip();
  215. index |= 1;
  216. }
  217. if (parameters.flipHorizontal)
  218. {
  219. if (!images[index|2])
  220. images[index|2] = images[index]->horizontalFlip();
  221. index |= 2;
  222. }
  223. return images[index];
  224. };
  225. const auto & flipAndDraw = [&](FlippedImages & images, const ColorRGBA & colorMultiplier, uint8_t alphaValue){
  226. getFlippedImage(images)->draw(where, parameters.palette, dest, src, colorMultiplier, alphaValue, locator.layer);
  227. };
  228. bool shadowLoading = scaled.at(scalingFactor).shadow.at(0) && scaled.at(scalingFactor).shadow.at(0)->isLoading();
  229. bool bodyLoading = scaled.at(scalingFactor).body.at(0) && scaled.at(scalingFactor).body.at(0)->isLoading();
  230. bool overlayLoading = scaled.at(scalingFactor).overlay.at(0) && scaled.at(scalingFactor).overlay.at(0)->isLoading();
  231. bool playerLoading = parameters.player != PlayerColor::CANNOT_DETERMINE && scaled.at(scalingFactor).playerColored.at(1+parameters.player.getNum()) && scaled.at(scalingFactor).playerColored.at(1+parameters.player.getNum())->isLoading();
  232. if (shadowLoading || bodyLoading || overlayLoading || playerLoading)
  233. {
  234. getFlippedImage(scaled[1].body)->scaledDraw(where, parameters.palette, dimensions() * scalingFactor, dest, src, parameters.colorMultiplier, parameters.alphaValue, locator.layer);
  235. return;
  236. }
  237. if (scaled.at(scalingFactor).shadow.at(0))
  238. flipAndDraw(scaled.at(scalingFactor).shadow, Colors::WHITE_TRUE, parameters.alphaValue);
  239. if (parameters.player != PlayerColor::CANNOT_DETERMINE && scaled.at(scalingFactor).playerColored.at(1+parameters.player.getNum()))
  240. {
  241. scaled.at(scalingFactor).playerColored.at(1+parameters.player.getNum())->draw(where, parameters.palette, dest, src, Colors::WHITE_TRUE, parameters.alphaValue, locator.layer);
  242. }
  243. else
  244. {
  245. if (scaled.at(scalingFactor).body.at(0))
  246. flipAndDraw(scaled.at(scalingFactor).body, parameters.colorMultiplier, parameters.alphaValue);
  247. }
  248. if (scaled.at(scalingFactor).overlay.at(0))
  249. flipAndDraw(scaled.at(scalingFactor).overlay, parameters.ovelayColorMultiplier, static_cast<int>(parameters.alphaValue) * parameters.ovelayColorMultiplier.a / 255);
  250. }
  251. const SDL_Palette * ScalableImageShared::getPalette() const
  252. {
  253. return scaled[1].body[0]->getPalette();
  254. }
  255. std::shared_ptr<ScalableImageInstance> ScalableImageShared::createImageReference()
  256. {
  257. return std::make_shared<ScalableImageInstance>(shared_from_this(), locator.layer);
  258. }
  259. ScalableImageInstance::ScalableImageInstance(const std::shared_ptr<ScalableImageShared> & image, EImageBlitMode blitMode)
  260. :image(image)
  261. ,parameters(image->getPalette(), blitMode)
  262. ,blitMode(blitMode)
  263. {
  264. assert(image);
  265. }
  266. void ScalableImageInstance::scaleTo(const Point & size, EScalingAlgorithm algorithm)
  267. {
  268. scaledImage = nullptr;
  269. auto newScaledImage = GH.renderHandler().createImage(dimensions(), CanvasScalingPolicy::AUTO);
  270. newScaledImage->getCanvas().draw(*this, Point(0, 0));
  271. newScaledImage->scaleTo(size, algorithm);
  272. scaledImage = newScaledImage;
  273. }
  274. void ScalableImageInstance::exportBitmap(const boost::filesystem::path & path) const
  275. {
  276. image->exportBitmap(path, parameters);
  277. }
  278. bool ScalableImageInstance::isTransparent(const Point & coords) const
  279. {
  280. return image->isTransparent(coords);
  281. }
  282. Rect ScalableImageInstance::contentRect() const
  283. {
  284. return image->contentRect();
  285. }
  286. Point ScalableImageInstance::dimensions() const
  287. {
  288. if (scaledImage)
  289. return scaledImage->dimensions() / GH.screenHandler().getScalingFactor();
  290. return image->dimensions();
  291. }
  292. void ScalableImageInstance::setAlpha(uint8_t value)
  293. {
  294. parameters.alphaValue = value;
  295. }
  296. void ScalableImageInstance::draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const
  297. {
  298. if (scaledImage)
  299. scaledImage->draw(where, pos, src, scalingFactor);
  300. else
  301. image->draw(where, pos, src, parameters, scalingFactor);
  302. }
  303. void ScalableImageInstance::setOverlayColor(const ColorRGBA & color)
  304. {
  305. parameters.ovelayColorMultiplier = color;
  306. if (parameters.palette)
  307. parameters.setOverlayColor(image->getPalette(), color, blitMode == EImageBlitMode::WITH_SHADOW_AND_SELECTION);
  308. }
  309. void ScalableImageInstance::playerColored(const PlayerColor & player)
  310. {
  311. parameters.player = player;
  312. if (parameters.palette)
  313. parameters.playerColored(player);
  314. image->preparePlayerColoredImage(player);
  315. }
  316. void ScalableImageParameters::playerColored(PlayerColor player)
  317. {
  318. graphics->setPlayerPalette(palette, player);
  319. }
  320. void ScalableImageInstance::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
  321. {
  322. if (parameters.palette)
  323. parameters.shiftPalette(image->getPalette(),firstColorID, colorsToMove, distanceToMove);
  324. }
  325. void ScalableImageInstance::adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask)
  326. {
  327. if (parameters.palette)
  328. parameters.adjustPalette(image->getPalette(), blitMode, shifter, colorsToSkipMask);
  329. }
  330. void ScalableImageInstance::horizontalFlip()
  331. {
  332. parameters.flipHorizontal = !parameters.flipHorizontal;
  333. }
  334. void ScalableImageInstance::verticalFlip()
  335. {
  336. parameters.flipVertical = !parameters.flipVertical;
  337. }
  338. std::shared_ptr<const ISharedImage> ScalableImageShared::loadOrGenerateImage(EImageBlitMode mode, int8_t scalingFactor, PlayerColor color, ImageType upscalingSource) const
  339. {
  340. ImageLocator loadingLocator;
  341. loadingLocator.image = locator.image;
  342. loadingLocator.defFile = locator.defFile;
  343. loadingLocator.defFrame = locator.defFrame;
  344. loadingLocator.defGroup = locator.defGroup;
  345. loadingLocator.layer = mode;
  346. loadingLocator.scalingFactor = scalingFactor;
  347. loadingLocator.playerColored = color;
  348. // best case - requested image is already available in filesystem
  349. auto loadedImage = GH.renderHandler().loadScaledImage(loadingLocator);
  350. if (loadedImage)
  351. return loadedImage;
  352. if (scalingFactor == 1)
  353. {
  354. // optional images for 1x resolution - only try load them, don't attempt to generate
  355. // this block should never be called for 'body' layer - that image is loaded unconditionally before construction
  356. assert(mode == EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR || mode == EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION || mode == EImageBlitMode::ONLY_FLAG_COLOR || mode == EImageBlitMode::ONLY_SELECTION || color != PlayerColor::CANNOT_DETERMINE);
  357. return nullptr;
  358. }
  359. // alternatively, find largest pre-scaled image, load it and rescale to desired scaling
  360. for (int8_t scaling = 4; scaling > 0; --scaling)
  361. {
  362. loadingLocator.scalingFactor = scaling;
  363. auto loadedImage = GH.renderHandler().loadScaledImage(loadingLocator);
  364. if (loadedImage)
  365. {
  366. if (scaling == 1)
  367. {
  368. if (mode == EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR || mode == EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION || mode == EImageBlitMode::ONLY_FLAG_COLOR || mode == EImageBlitMode::ONLY_SELECTION || color != PlayerColor::CANNOT_DETERMINE)
  369. {
  370. ScalableImageParameters parameters(getPalette(), mode);
  371. return loadedImage->scaleInteger(scalingFactor, parameters.palette, mode);
  372. }
  373. }
  374. else
  375. {
  376. Point targetSize = scaled[1].body[0]->dimensions() * scalingFactor;
  377. return loadedImage->scaleTo(targetSize, nullptr);
  378. }
  379. }
  380. }
  381. ScalableImageParameters parameters(getPalette(), mode);
  382. // if all else fails - use base (presumably, indexed) image and convert it to desired form
  383. if (color != PlayerColor::CANNOT_DETERMINE)
  384. parameters.playerColored(color);
  385. if (upscalingSource)
  386. return upscalingSource->scaleInteger(scalingFactor, parameters.palette, mode);
  387. else
  388. return scaled[1].body[0]->scaleInteger(scalingFactor, parameters.palette, mode);
  389. }
  390. void ScalableImageShared::loadScaledImages(int8_t scalingFactor, PlayerColor color)
  391. {
  392. if (scaled[scalingFactor].body[0] == nullptr && scalingFactor != 1)
  393. {
  394. switch(locator.layer)
  395. {
  396. case EImageBlitMode::OPAQUE:
  397. case EImageBlitMode::COLORKEY:
  398. case EImageBlitMode::SIMPLE:
  399. scaled[scalingFactor].body[0] = loadOrGenerateImage(locator.layer, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
  400. break;
  401. case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
  402. case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
  403. scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_SELECTION, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
  404. break;
  405. case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
  406. case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
  407. scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
  408. break;
  409. case EImageBlitMode::WITH_SHADOW:
  410. case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
  411. scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
  412. break;
  413. }
  414. }
  415. if (color != PlayerColor::CANNOT_DETERMINE && scaled[scalingFactor].playerColored[1+color.getNum()] == nullptr)
  416. {
  417. switch(locator.layer)
  418. {
  419. case EImageBlitMode::OPAQUE:
  420. case EImageBlitMode::COLORKEY:
  421. case EImageBlitMode::SIMPLE:
  422. scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(locator.layer, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
  423. break;
  424. case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
  425. case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
  426. scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_SELECTION, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
  427. break;
  428. case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
  429. case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
  430. scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
  431. break;
  432. case EImageBlitMode::WITH_SHADOW:
  433. case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
  434. scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
  435. break;
  436. }
  437. }
  438. if (scaled[scalingFactor].shadow[0] == nullptr)
  439. {
  440. switch(locator.layer)
  441. {
  442. case EImageBlitMode::WITH_SHADOW:
  443. case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
  444. case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
  445. scaled[scalingFactor].shadow[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].shadow[0]);
  446. break;
  447. case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
  448. case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
  449. scaled[scalingFactor].shadow[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].shadow[0]);
  450. break;
  451. default:
  452. break;
  453. }
  454. }
  455. if (scaled[scalingFactor].overlay[0] == nullptr)
  456. {
  457. switch(locator.layer)
  458. {
  459. case EImageBlitMode::ONLY_FLAG_COLOR:
  460. case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
  461. scaled[scalingFactor].overlay[0] = loadOrGenerateImage(EImageBlitMode::ONLY_FLAG_COLOR, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].overlay[0]);
  462. break;
  463. case EImageBlitMode::ONLY_SELECTION:
  464. case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
  465. scaled[scalingFactor].overlay[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SELECTION, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].overlay[0]);
  466. break;
  467. default:
  468. break;
  469. }
  470. }
  471. }
  472. void ScalableImageShared::preparePlayerColoredImage(PlayerColor color)
  473. {
  474. loadScaledImages(GH.screenHandler().getScalingFactor(), color);
  475. }