AssetGenerator.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. /*
  2. * AssetGenerator.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 "AssetGenerator.h"
  12. #include "../GameEngine.h"
  13. #include "../render/IImage.h"
  14. #include "../render/IImageLoader.h"
  15. #include "../render/Canvas.h"
  16. #include "../render/CanvasImage.h"
  17. #include "../render/ColorFilter.h"
  18. #include "../render/IRenderHandler.h"
  19. #include "../render/CAnimation.h"
  20. #include "../render/Colors.h"
  21. #include "../lib/filesystem/Filesystem.h"
  22. #include "../lib/GameSettings.h"
  23. #include "../lib/IGameSettings.h"
  24. #include "../lib/json/JsonNode.h"
  25. #include "../lib/VCMIDirs.h"
  26. #include "../lib/GameLibrary.h"
  27. #include "../lib/RiverHandler.h"
  28. #include "../lib/RoadHandler.h"
  29. #include "../lib/TerrainHandler.h"
  30. void AssetGenerator::initialize()
  31. {
  32. // clear to avoid non updated sprites after mod change (if base imnages are used)
  33. if(boost::filesystem::is_directory(VCMIDirs::get().userDataPath() / "Generated"))
  34. boost::filesystem::remove_all(VCMIDirs::get().userDataPath() / "Generated");
  35. imageFiles[ImagePath::builtin("AdventureOptionsBackgroundClear.png")] = [this](){ return createAdventureOptionsCleanBackground();};
  36. imageFiles[ImagePath::builtin("SpellBookLarge.png")] = [this](){ return createBigSpellBook();};
  37. imageFiles[ImagePath::builtin("combatUnitNumberWindowDefault.png")] = [this](){ return createCombatUnitNumberWindow(0.6f, 0.2f, 1.0f);};
  38. imageFiles[ImagePath::builtin("combatUnitNumberWindowNeutral.png")] = [this](){ return createCombatUnitNumberWindow(1.0f, 1.0f, 2.0f);};
  39. imageFiles[ImagePath::builtin("combatUnitNumberWindowPositive.png")] = [this](){ return createCombatUnitNumberWindow(0.2f, 1.0f, 0.2f);};
  40. imageFiles[ImagePath::builtin("combatUnitNumberWindowNegative.png")] = [this](){ return createCombatUnitNumberWindow(1.0f, 0.2f, 0.2f);};
  41. imageFiles[ImagePath::builtin("CampaignBackground4.png")] = [this]() { return createCampaignBackground(4); };
  42. imageFiles[ImagePath::builtin("CampaignBackground5.png")] = [this]() { return createCampaignBackground(5); };
  43. imageFiles[ImagePath::builtin("CampaignBackground6.png")] = [this]() { return createCampaignBackground(6); };
  44. imageFiles[ImagePath::builtin("CampaignBackground7.png")] = [this]() { return createCampaignBackground(7); };
  45. imageFiles[ImagePath::builtin("CampaignBackground8.png")] = [this]() { return createCampaignBackground(8); };
  46. imageFiles[ImagePath::builtin("SpelTabNone.png")] = [this](){ return createSpellTabNone();};
  47. for (PlayerColor color(-1); color < PlayerColor::PLAYER_LIMIT; ++color)
  48. {
  49. std::string name = "ResBarElement" + (color == -1 ? "" : "-" + color.toString());
  50. imageFiles[ImagePath::builtin(name)] = [this, color](){ return createResBarElement(std::max(PlayerColor(0), color));};
  51. }
  52. for (PlayerColor color(-1); color < PlayerColor::PLAYER_LIMIT; ++color)
  53. {
  54. for(int amount : { 8, 9 })
  55. {
  56. auto addResWindow = [this, amount, color](std::string baseName, CreateResourceWindowType type){
  57. std::string name = baseName + "-R" + std::to_string(amount) + (color == -1 ? "" : "-" + color.toString());
  58. imageFiles[ImagePath::builtin(name)] = [this, color, amount, type](){ return createResourceWindow(type, amount, std::max(PlayerColor(0), color)); };
  59. };
  60. addResWindow("TPMRKABS", CreateResourceWindowType::ARTIFACTS_BUYING);
  61. addResWindow("TPMRKASS", CreateResourceWindowType::ARTIFACTS_SELLING);
  62. addResWindow("TPMRKRES", CreateResourceWindowType::MARKET_RESOURCES);
  63. addResWindow("TPMRKCRS", CreateResourceWindowType::FREELANCERS_GUILD);
  64. addResWindow("TPMRKPTS", CreateResourceWindowType::TRANSFER_RESOURCES);
  65. }
  66. }
  67. imageFiles[ImagePath::builtin("stackWindow/info-panel-0.png")] = [this](){ return createCreatureInfoPanel(2);};
  68. imageFiles[ImagePath::builtin("stackWindow/info-panel-1.png")] = [this](){ return createCreatureInfoPanel(3);};
  69. imageFiles[ImagePath::builtin("stackWindow/info-panel-2.png")] = [this](){ return createCreatureInfoPanel(4);};
  70. imageFiles[ImagePath::builtin("stackWindow/bonus-effects.png")] = [this](){ return createCreatureInfoPanelElement(BONUS_EFFECTS);};
  71. imageFiles[ImagePath::builtin("stackWindow/spell-effects.png")] = [this](){ return createCreatureInfoPanelElement(SPELL_EFFECTS);};
  72. imageFiles[ImagePath::builtin("stackWindow/button-panel.png")] = [this](){ return createCreatureInfoPanelElement(BUTTON_PANEL);};
  73. imageFiles[ImagePath::builtin("stackWindow/commander-bg.png")] = [this](){ return createCreatureInfoPanelElement(COMMANDER_BACKGROUND);};
  74. imageFiles[ImagePath::builtin("stackWindow/commander-abilities.png")] = [this](){ return createCreatureInfoPanelElement(COMMANDER_ABILITIES);};
  75. imageFiles[ImagePath::builtin("questDialog.png")] = [this](){ return createQuestWindow();};
  76. for (PlayerColor color(0); color < PlayerColor::PLAYER_LIMIT; ++color)
  77. imageFiles[ImagePath::builtin("DialogBoxBackground_" + color.toString())] = [this, color](){ return createPlayerColoredBackground(color);};
  78. for(int i = 1; i < 9; i++)
  79. imageFiles[ImagePath::builtin("CampaignHc" + std::to_string(i) + "Image.png")] = [this, i](){ return createChroniclesCampaignImages(i);};
  80. animationFiles[AnimationPath::builtin("SPRITES/adventureLayersButton")] = createAdventureMapButton(ImagePath::builtin("adventureLayers.png"), true);
  81. animationFiles[AnimationPath::builtin("SPRITES/GSPButtonClear")] = createGSPButtonClear();
  82. for (PlayerColor color(-1); color < PlayerColor::PLAYER_LIMIT; ++color)
  83. {
  84. std::string name = "TownPortalBackgroundBlue" + (color == -1 ? "" : "-" + color.toString());
  85. imageFiles[ImagePath::builtin(name)] = [this, color](){ return createGateListColored(std::max(PlayerColor(0), color), PlayerColor(1)); };
  86. }
  87. imageFiles[ImagePath::builtin("heroSlotsBlue.png")] = [this](){ return createHeroSlotsColored(PlayerColor(1));};
  88. createPaletteShiftedSprites();
  89. }
  90. std::shared_ptr<ISharedImage> AssetGenerator::generateImage(const ImagePath & image)
  91. {
  92. if (imageFiles.count(image))
  93. return imageFiles.at(image)()->toSharedImage(); // TODO: cache?
  94. else
  95. return nullptr;
  96. }
  97. std::map<ImagePath, std::shared_ptr<ISharedImage>> AssetGenerator::generateAllImages()
  98. {
  99. std::map<ImagePath, std::shared_ptr<ISharedImage>> result;
  100. for (const auto & entry : imageFiles)
  101. result[entry.first] = entry.second()->toSharedImage();
  102. return result;
  103. }
  104. std::map<AnimationPath, AssetGenerator::AnimationLayoutMap> AssetGenerator::generateAllAnimations()
  105. {
  106. return animationFiles;
  107. }
  108. void AssetGenerator::addImageFile(const ImagePath & path, ImageGenerationFunctor & img)
  109. {
  110. imageFiles[path] = img;
  111. }
  112. void AssetGenerator::addAnimationFile(const AnimationPath & path, AnimationLayoutMap & anim)
  113. {
  114. animationFiles[path] = anim;
  115. }
  116. auto getColorFilters()
  117. {
  118. auto filterSettings = LIBRARY->settingsHandler->getFullConfig()["interface"]["playerColoredBackground"];
  119. static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = {
  120. ColorFilter::genRangeShifter( filterSettings["red" ].convertTo<std::vector<float>>() ),
  121. ColorFilter::genRangeShifter( filterSettings["blue" ].convertTo<std::vector<float>>() ),
  122. ColorFilter::genRangeShifter( filterSettings["tan" ].convertTo<std::vector<float>>() ),
  123. ColorFilter::genRangeShifter( filterSettings["green" ].convertTo<std::vector<float>>() ),
  124. ColorFilter::genRangeShifter( filterSettings["orange"].convertTo<std::vector<float>>() ),
  125. ColorFilter::genRangeShifter( filterSettings["purple"].convertTo<std::vector<float>>() ),
  126. ColorFilter::genRangeShifter( filterSettings["teal" ].convertTo<std::vector<float>>() ),
  127. ColorFilter::genRangeShifter( filterSettings["pink" ].convertTo<std::vector<float>>() )
  128. };
  129. return filters;
  130. }
  131. AssetGenerator::CanvasPtr AssetGenerator::createAdventureOptionsCleanBackground() const
  132. {
  133. auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"), EImageBlitMode::OPAQUE);
  134. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  135. auto image = ENGINE->renderHandler().createImage(Point(575, 585), CanvasScalingPolicy::IGNORE);
  136. Canvas canvas = image->getCanvas();
  137. canvas.draw(img, Point(0, 0), Rect(0, 0, 575, 585));
  138. canvas.draw(img, Point(54, 121), Rect(54, 123, 335, 1));
  139. canvas.draw(img, Point(158, 84), Rect(156, 84, 2, 37));
  140. canvas.draw(img, Point(234, 84), Rect(232, 84, 2, 37));
  141. canvas.draw(img, Point(310, 84), Rect(308, 84, 2, 37));
  142. canvas.draw(img, Point(53, 567), Rect(53, 520, 339, 3));
  143. canvas.draw(img, Point(53, 520), Rect(53, 264, 339, 47));
  144. return image;
  145. }
  146. AssetGenerator::CanvasPtr AssetGenerator::createBigSpellBook() const
  147. {
  148. auto locator = ImageLocator(ImagePath::builtin("SpelBack"), EImageBlitMode::OPAQUE);
  149. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  150. auto image = ENGINE->renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
  151. Canvas canvas = image->getCanvas();
  152. // edges
  153. canvas.draw(img, Point(0, 0), Rect(15, 38, 90, 45));
  154. canvas.draw(img, Point(0, 460), Rect(15, 400, 90, 141));
  155. canvas.draw(img, Point(705, 0), Rect(509, 38, 95, 45));
  156. canvas.draw(img, Point(705, 460), Rect(509, 400, 95, 141));
  157. // left / right
  158. Canvas tmp1 = Canvas(Point(90, 355 - 45), CanvasScalingPolicy::IGNORE);
  159. tmp1.draw(img, Point(0, 0), Rect(15, 38 + 45, 90, 355 - 45));
  160. canvas.drawScaled(tmp1, Point(0, 45), Point(90, 415));
  161. Canvas tmp2 = Canvas(Point(95, 355 - 45), CanvasScalingPolicy::IGNORE);
  162. tmp2.draw(img, Point(0, 0), Rect(509, 38 + 45, 95, 355 - 45));
  163. canvas.drawScaled(tmp2, Point(705, 45), Point(95, 415));
  164. // top / bottom
  165. Canvas tmp3 = Canvas(Point(409, 45), CanvasScalingPolicy::IGNORE);
  166. tmp3.draw(img, Point(0, 0), Rect(100, 38, 409, 45));
  167. canvas.drawScaled(tmp3, Point(90, 0), Point(615, 45));
  168. Canvas tmp4 = Canvas(Point(409, 141), CanvasScalingPolicy::IGNORE);
  169. tmp4.draw(img, Point(0, 0), Rect(100, 400, 409, 141));
  170. canvas.drawScaled(tmp4, Point(90, 460), Point(615, 141));
  171. // middle
  172. Canvas tmp5 = Canvas(Point(409, 141), CanvasScalingPolicy::IGNORE);
  173. tmp5.draw(img, Point(0, 0), Rect(100, 38 + 45, 509 - 15, 400 - 38));
  174. canvas.drawScaled(tmp5, Point(90, 45), Point(615, 415));
  175. // carpet
  176. Canvas tmp6 = Canvas(Point(590, 59), CanvasScalingPolicy::IGNORE);
  177. tmp6.draw(img, Point(0, 0), Rect(15, 484, 590, 59));
  178. canvas.drawScaled(tmp6, Point(0, 545), Point(800, 59));
  179. // remove bookmarks
  180. for (int i = 0; i < 56; i++)
  181. canvas.draw(Canvas(canvas, Rect(i < 30 ? 268 : 327, 464, 1, 46)), Point(269 + i, 464));
  182. for (int i = 0; i < 56; i++)
  183. canvas.draw(Canvas(canvas, Rect(469, 464, 1, 42)), Point(470 + i, 464));
  184. for (int i = 0; i < 57; i++)
  185. canvas.draw(Canvas(canvas, Rect(i < 30 ? 564 : 630, 464, 1, 44)), Point(565 + i, 464));
  186. for (int i = 0; i < 56; i++)
  187. canvas.draw(Canvas(canvas, Rect(656, 464, 1, 47)), Point(657 + i, 464));
  188. // draw bookmarks
  189. canvas.draw(img, Point(278, 464), Rect(220, 405, 37, 47));
  190. canvas.draw(img, Point(481, 465), Rect(354, 406, 37, 41));
  191. canvas.draw(img, Point(575, 465), Rect(417, 406, 37, 45));
  192. canvas.draw(img, Point(667, 465), Rect(478, 406, 37, 47));
  193. return image;
  194. }
  195. AssetGenerator::CanvasPtr AssetGenerator::createPlayerColoredBackground(const PlayerColor & player) const
  196. {
  197. auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"), EImageBlitMode::OPAQUE);
  198. std::shared_ptr<IImage> texture = ENGINE->renderHandler().loadImage(locator);
  199. // transform to make color of brown DIBOX.PCX texture match color of specified player
  200. static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = getColorFilters();
  201. assert(player.isValidPlayer());
  202. if (!player.isValidPlayer())
  203. throw std::runtime_error("Unable to colorize to invalid player color" + std::to_string(player.getNum()));
  204. texture->adjustPalette(filters[player.getNum()], 0);
  205. auto image = ENGINE->renderHandler().createImage(texture->dimensions(), CanvasScalingPolicy::IGNORE);
  206. Canvas canvas = image->getCanvas();
  207. canvas.draw(texture, Point(0,0));
  208. return image;
  209. }
  210. AssetGenerator::CanvasPtr AssetGenerator::createCombatUnitNumberWindow(float multR, float multG, float multB) const
  211. {
  212. auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"), EImageBlitMode::OPAQUE);
  213. locator.layer = EImageBlitMode::OPAQUE;
  214. std::shared_ptr<IImage> texture = ENGINE->renderHandler().loadImage(locator);
  215. const auto shifter= ColorFilter::genRangeShifter(0.f, 0.f, 0.f, multR, multG, multB);
  216. // do not change border color
  217. static const int32_t ignoredMask = 1 << 26;
  218. texture->adjustPalette(shifter, ignoredMask);
  219. auto image = ENGINE->renderHandler().createImage(texture->dimensions(), CanvasScalingPolicy::IGNORE);
  220. Canvas canvas = image->getCanvas();
  221. canvas.draw(texture, Point(0,0));
  222. return image;
  223. }
  224. AssetGenerator::CanvasPtr AssetGenerator::createCampaignBackground(int selection) const
  225. {
  226. auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
  227. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  228. auto image = ENGINE->renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
  229. Canvas canvas = image->getCanvas();
  230. canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
  231. // BigBlock section
  232. auto bigBlock = ENGINE->renderHandler().createImage(Point(248, 114), CanvasScalingPolicy::IGNORE);
  233. Rect bigBlockRegion(292, 74, 248, 114);
  234. Canvas croppedBigBlock = bigBlock->getCanvas();
  235. croppedBigBlock.draw(img, Point(0, 0), bigBlockRegion);
  236. Point bigBlockSize(200, 114);
  237. // SmallBlock section
  238. auto smallBlock = ENGINE->renderHandler().createImage(Point(248, 114), CanvasScalingPolicy::IGNORE);
  239. Canvas croppedSmallBlock = smallBlock->getCanvas();
  240. croppedSmallBlock.draw(img, Point(0, 0), bigBlockRegion);
  241. Point smallBlockSize(134, 114);
  242. // Tripple block section
  243. auto trippleBlock = ENGINE->renderHandler().createImage(Point(72, 116), CanvasScalingPolicy::IGNORE);
  244. Rect trippleBlockSection(512, 246, 72, 116);
  245. Canvas croppedTrippleBlock = trippleBlock->getCanvas();
  246. croppedTrippleBlock.draw(img, Point(0, 0), trippleBlockSection);
  247. Point trippleBlockSize(70, 114);
  248. // First campaigns line
  249. if (selection > 7)
  250. {
  251. // Rebuild 1. campaigns line from 2 to 3 fields
  252. canvas.drawScaled(bigBlock->getCanvas(), Point(40, 72), bigBlockSize);
  253. canvas.drawScaled(trippleBlock->getCanvas(), Point(240, 73), trippleBlockSize);
  254. canvas.drawScaled(bigBlock->getCanvas(), Point(310, 72), bigBlockSize);
  255. canvas.drawScaled(trippleBlock->getCanvas(), Point(510, 72), trippleBlockSize);
  256. canvas.drawScaled(bigBlock->getCanvas(), Point(580, 72), bigBlockSize);
  257. canvas.drawScaled(trippleBlock->getCanvas(), Point(780, 72), trippleBlockSize);
  258. }
  259. else
  260. {
  261. // Empty 1 + 2. field
  262. canvas.drawScaled(bigBlock->getCanvas(), Point(90, 72), bigBlockSize);
  263. canvas.drawScaled(bigBlock->getCanvas(), Point(540, 72), bigBlockSize);
  264. }
  265. // Second campaigns line
  266. // 3. Field
  267. canvas.drawScaled(bigBlock->getCanvas(), Point(43, 245), bigBlockSize);
  268. if (selection == 4)
  269. {
  270. // Disabled 4. field
  271. canvas.drawScaled(trippleBlock->getCanvas(), Point(310, 245), trippleBlockSize);
  272. canvas.drawScaled(smallBlock->getCanvas(), Point(380, 245), smallBlockSize);
  273. }
  274. else
  275. {
  276. // Empty 4. field
  277. canvas.drawScaled(bigBlock->getCanvas(), Point(314, 244), bigBlockSize);
  278. }
  279. // 5. Field
  280. canvas.drawScaled(bigBlock->getCanvas(), Point(586, 246), bigBlockSize);
  281. // Third campaigns line
  282. // 6. Field
  283. if (selection >= 6)
  284. {
  285. canvas.drawScaled(bigBlock->getCanvas(), Point(32, 417), bigBlockSize);
  286. }
  287. else
  288. {
  289. canvas.drawScaled(trippleBlock->getCanvas(), Point(30, 417), trippleBlockSize);
  290. canvas.drawScaled(smallBlock->getCanvas(), Point(100, 417), smallBlockSize);
  291. }
  292. auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"), EImageBlitMode::OPAQUE);
  293. std::shared_ptr<IImage> imgSkull = ENGINE->renderHandler().loadImage(locatorSkull);
  294. if (selection >= 7)
  295. {
  296. // Only skull part
  297. canvas.drawScaled(bigBlock->getCanvas(), Point(404, 417), bigBlockSize);
  298. canvas.draw(imgSkull, Point(563, 512), Rect(178, 108, 43, 19));
  299. }
  300. else
  301. {
  302. // Original disabled field with skull and stone for 8. field
  303. Canvas canvasSkull = Canvas(Point(imgSkull->width(), imgSkull->height()), CanvasScalingPolicy::IGNORE);
  304. canvasSkull.draw(imgSkull, Point(0, 0), Rect(0, 0, imgSkull->width(), imgSkull->height()));
  305. canvas.drawScaled(canvasSkull, Point(385, 400), Point(238, 150));
  306. }
  307. return image;
  308. }
  309. AssetGenerator::CanvasPtr AssetGenerator::createResBarElement(const PlayerColor & player) const
  310. {
  311. auto locator = ImageLocator(ImagePath::builtin("ARESBAR"), EImageBlitMode::COLORKEY);
  312. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  313. img->playerColored(player);
  314. auto image = ENGINE->renderHandler().createImage(Point(84, 22), CanvasScalingPolicy::IGNORE);
  315. Canvas canvas = image->getCanvas();
  316. canvas.draw(img, Point(0, 0), Rect(2, 0, 84, 22));
  317. canvas.draw(img, Point(4, 0), Rect(29, 0, 22, 22));
  318. return image;
  319. }
  320. AssetGenerator::CanvasPtr AssetGenerator::createSpellTabNone() const
  321. {
  322. auto img1 = ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("SPELTAB"), EImageBlitMode::COLORKEY)->getImage(0);
  323. auto img2 = ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("SPELTAB"), EImageBlitMode::COLORKEY)->getImage(4);
  324. auto image = ENGINE->renderHandler().createImage(img1->dimensions(), CanvasScalingPolicy::IGNORE);
  325. Canvas canvas = image->getCanvas();
  326. canvas.draw(img1, Point(0, img1->height() / 2), Rect(0, img1->height() / 2, img1->width(), img1->height() / 2));
  327. canvas.draw(img2, Point(0, 0), Rect(0, 0, img2->width(), img2->height() / 2));
  328. return image;
  329. }
  330. AssetGenerator::CanvasPtr AssetGenerator::createChroniclesCampaignImages(int chronicle) const
  331. {
  332. auto imgPathBg = ImagePath::builtin("chronicles_" + std::to_string(chronicle) + "/GamSelBk");
  333. auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
  334. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  335. auto image = ENGINE->renderHandler().createImage(Point(200, 116), CanvasScalingPolicy::IGNORE);
  336. Canvas canvas = image->getCanvas();
  337. std::array sourceRect = {
  338. Rect(149, 144, 200, 116),
  339. Rect(156, 150, 200, 116),
  340. Rect(171, 153, 200, 116),
  341. Rect(35, 358, 200, 116),
  342. Rect(216, 248, 200, 116),
  343. Rect(58, 234, 200, 116),
  344. Rect(184, 219, 200, 116),
  345. Rect(268, 210, 200, 116),
  346. };
  347. canvas.draw(img, Point(0, 0), sourceRect.at(chronicle-1));
  348. if (chronicle == 8)
  349. {
  350. //skull
  351. auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"), EImageBlitMode::OPAQUE);
  352. std::shared_ptr<IImage> imgSkull = ENGINE->renderHandler().loadImage(locatorSkull);
  353. canvas.draw(imgSkull, Point(162, 94), Rect(162, 94, 41, 22));
  354. canvas.draw(img, Point(162, 94), Rect(424, 304, 14, 4));
  355. canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
  356. canvas.draw(img, Point(158, 102), Rect(424, 312, 10, 4));
  357. canvas.draw(img, Point(154, 106), Rect(424, 316, 10, 4));
  358. }
  359. return image;
  360. }
  361. void AssetGenerator::createPaletteShiftedSprites()
  362. {
  363. for(auto entity : LIBRARY->terrainTypeHandler->objects)
  364. {
  365. if(entity->paletteAnimation.empty())
  366. continue;
  367. std::vector<PaletteAnimation> paletteShifts;
  368. for(auto & animEntity : entity->paletteAnimation)
  369. paletteShifts.push_back({animEntity.start, animEntity.length});
  370. generatePaletteShiftedAnimation(entity->tilesFilename, paletteShifts);
  371. }
  372. for(auto entity : LIBRARY->riverTypeHandler->objects)
  373. {
  374. if(entity->paletteAnimation.empty())
  375. continue;
  376. std::vector<PaletteAnimation> paletteShifts;
  377. for(auto & animEntity : entity->paletteAnimation)
  378. paletteShifts.push_back({animEntity.start, animEntity.length});
  379. generatePaletteShiftedAnimation(entity->tilesFilename, paletteShifts);
  380. }
  381. }
  382. void AssetGenerator::generatePaletteShiftedAnimation(const AnimationPath & sprite, const std::vector<PaletteAnimation> & paletteAnimations)
  383. {
  384. AnimationLayoutMap layout;
  385. auto animation = ENGINE->renderHandler().loadAnimation(sprite, EImageBlitMode::COLORKEY);
  386. int paletteTransformLength = 1;
  387. for (const auto & transform : paletteAnimations)
  388. paletteTransformLength = std::lcm(paletteTransformLength, transform.length);
  389. for(int tileIndex = 0; tileIndex < animation->size(); tileIndex++)
  390. {
  391. for(int paletteIndex = 0; paletteIndex < paletteTransformLength; paletteIndex++)
  392. {
  393. ImagePath spriteName = ImagePath::builtin(sprite.getName() + boost::str(boost::format("%02d") % tileIndex) + "_" + std::to_string(paletteIndex) + ".png");
  394. layout[paletteIndex].push_back(ImageLocator(spriteName, EImageBlitMode::SIMPLE));
  395. imageFiles[spriteName] = [this, sprite, paletteAnimations, tileIndex, paletteIndex](){
  396. return createPaletteShiftedImage(sprite, paletteAnimations, tileIndex, paletteIndex);
  397. };
  398. }
  399. }
  400. AnimationPath shiftedPath = AnimationPath::builtin("SPRITES/" + sprite.getName() + "_SHIFTED");
  401. animationFiles[shiftedPath] = layout;
  402. }
  403. AssetGenerator::CanvasPtr AssetGenerator::createPaletteShiftedImage(const AnimationPath & source, const std::vector<PaletteAnimation> & palette, int frameIndex, int paletteShiftCounter) const
  404. {
  405. auto animation = ENGINE->renderHandler().loadAnimation(source, EImageBlitMode::COLORKEY);
  406. auto imgLoc = animation->getImageLocator(frameIndex, 0);
  407. auto img = ENGINE->renderHandler().loadImage(imgLoc);
  408. for(const auto & element : palette)
  409. img->shiftPalette(element.start, element.length, paletteShiftCounter % element.length);
  410. auto image = ENGINE->renderHandler().createImage(Point(32, 32), CanvasScalingPolicy::IGNORE);
  411. Canvas canvas = image->getCanvas();
  412. canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
  413. return image;
  414. }
  415. void meanImage(AssetGenerator::CanvasPtr dst, std::vector<Canvas> & images)
  416. {
  417. auto image = dst->getCanvas();
  418. for(int x = 0; x < dst->width(); x++)
  419. for(int y = 0; y < dst->height(); y++)
  420. {
  421. int sumR = 0;
  422. int sumG = 0;
  423. int sumB = 0;
  424. int sumA = 0;
  425. for(auto & img : images)
  426. {
  427. auto color = img.getPixel(Point(x, y));
  428. sumR += color.r;
  429. sumG += color.g;
  430. sumB += color.b;
  431. sumA += color.a;
  432. }
  433. int ct = images.size();
  434. image.drawPoint(Point(x, y), ColorRGBA(sumR / ct, sumG / ct, sumB / ct, sumA / ct));
  435. }
  436. }
  437. AssetGenerator::CanvasPtr AssetGenerator::createAdventureMapButtonClear(const PlayerColor & player, bool small) const
  438. {
  439. CanvasPtr dst = nullptr;
  440. if(small)
  441. {
  442. auto imageNames = { "iam002", "iam003", "iam004", "iam005", "iam006", "iam007", "iam008", "iam009", "iam010", "iam011" };
  443. std::vector<Canvas> images;
  444. for(auto & imageName : imageNames)
  445. {
  446. auto animation = ENGINE->renderHandler().loadAnimation(AnimationPath::builtin(imageName), EImageBlitMode::COLORKEY);
  447. animation->playerColored(player);
  448. auto image = ENGINE->renderHandler().createImage(animation->getImage(2)->dimensions(), CanvasScalingPolicy::IGNORE);
  449. if(!dst)
  450. dst = ENGINE->renderHandler().createImage(animation->getImage(2)->dimensions(), CanvasScalingPolicy::IGNORE);
  451. Canvas canvas = image->getCanvas();
  452. canvas.draw(animation->getImage(2), Point(0, 0));
  453. images.push_back(image->getCanvas());
  454. }
  455. meanImage(dst, images);
  456. }
  457. else
  458. {
  459. auto animation = ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("iam001"), EImageBlitMode::COLORKEY);
  460. animation->playerColored(player);
  461. auto image = animation->getImage(2);
  462. dst = ENGINE->renderHandler().createImage(image->dimensions(), CanvasScalingPolicy::IGNORE);
  463. Canvas canvas = dst->getCanvas();
  464. canvas.draw(image, Point(0, 0));
  465. auto tmp = ENGINE->renderHandler().createImage(Point(5, 22), CanvasScalingPolicy::IGNORE);
  466. std::vector<Canvas> meanImages;
  467. auto tmpLeft = ENGINE->renderHandler().createImage(Point(5, 22), CanvasScalingPolicy::IGNORE);
  468. tmpLeft->getCanvas().draw(image, Point(0, 0), Rect(18, 6, 5, 22));
  469. meanImages.push_back(tmpLeft->getCanvas());
  470. auto tmpRight = ENGINE->renderHandler().createImage(Point(5, 22), CanvasScalingPolicy::IGNORE);
  471. tmpRight->getCanvas().draw(image, Point(0, 0), Rect(42, 6, 5, 22));
  472. meanImages.push_back(tmpRight->getCanvas());
  473. meanImage(tmp, meanImages);
  474. for(int i = 0; i < 4; i++)
  475. canvas.draw(tmp, Point(23 + i * 5, 6));
  476. }
  477. return dst;
  478. }
  479. AssetGenerator::AnimationLayoutMap AssetGenerator::createAdventureMapButton(const ImagePath & overlay, bool small)
  480. {
  481. std::shared_ptr<IImage> overlayImg = ENGINE->renderHandler().loadImage(ImageLocator(overlay, EImageBlitMode::OPAQUE));
  482. auto overlayCanvasImg = ENGINE->renderHandler().createImage(overlayImg->dimensions(), CanvasScalingPolicy::IGNORE);
  483. Canvas overlayCanvas = overlayCanvasImg->getCanvas();
  484. overlayCanvas.draw(overlayImg, Point(0, 0));
  485. AnimationLayoutMap layout;
  486. for (PlayerColor color(0); color < PlayerColor::PLAYER_LIMIT; ++color)
  487. {
  488. int offs = small ? 0 : 16;
  489. auto clearButtonImg = createAdventureMapButtonClear(color, small);
  490. for(int i = 0; i < 4; i++)
  491. {
  492. std::string baseName = overlay.getOriginalName() + "Btn" + (small ? "Small" : "Big") + std::to_string(i);
  493. ImagePath spriteName = ImagePath::builtin(baseName + ".png");
  494. ImagePath spriteNameColor = ImagePath::builtin(baseName + "-" + color.toString() + ".png");
  495. imageFiles[spriteNameColor] = [overlayCanvasImg, clearButtonImg, i, offs](){
  496. auto newImg = ENGINE->renderHandler().createImage(clearButtonImg->dimensions(), CanvasScalingPolicy::IGNORE);
  497. auto canvas = newImg->getCanvas();
  498. canvas.draw(clearButtonImg, Point(0, 0));
  499. switch (i)
  500. {
  501. case 0:
  502. canvas.draw(overlayCanvasImg, Point(offs, 0));
  503. return newImg;
  504. case 1:
  505. canvas.draw(clearButtonImg, Point(1, 1));
  506. canvas.draw(overlayCanvasImg, Point(offs + 1, 1));
  507. canvas.drawLine(Point(0, 0), Point(newImg->width() - 1, 0), ColorRGBA(0, 0, 0), ColorRGBA(0, 0, 0));
  508. canvas.drawLine(Point(0, 0), Point(0, newImg->height() - 1), ColorRGBA(0, 0, 0), ColorRGBA(0, 0, 0));
  509. canvas.drawColorBlended(Rect(0, 0, newImg->width(), 4), ColorRGBA(0, 0, 0, 160));
  510. canvas.drawColorBlended(Rect(0, 0, 4, newImg->height()), ColorRGBA(0, 0, 0, 160));
  511. return newImg;
  512. case 2:
  513. canvas.drawTransparent(overlayCanvasImg->getCanvas(), Point(offs, 0), 0.25);
  514. return newImg;
  515. default:
  516. canvas.draw(overlayCanvasImg, Point(offs, 0));
  517. canvas.drawLine(Point(0, 0), Point(newImg->width() - 1, 0), ColorRGBA(255, 255, 255), ColorRGBA(255, 255, 255));
  518. canvas.drawLine(Point(newImg->width() - 1, 0), Point(newImg->width() - 1, newImg->height() - 1), ColorRGBA(255, 255, 255), ColorRGBA(255, 255, 255));
  519. canvas.drawLine(Point(newImg->width() - 1, newImg->height() - 1), Point(0, newImg->height() - 1), ColorRGBA(255, 255, 255), ColorRGBA(255, 255, 255));
  520. canvas.drawLine(Point(0, newImg->height() - 1), Point(0, 0), ColorRGBA(255, 255, 255), ColorRGBA(255, 255, 255));
  521. return newImg;
  522. }
  523. };
  524. if(color == PlayerColor(0))
  525. {
  526. layout[0].push_back(ImageLocator(spriteName, EImageBlitMode::SIMPLE));
  527. imageFiles[spriteName] = imageFiles[spriteNameColor];
  528. }
  529. }
  530. }
  531. return layout;
  532. }
  533. AssetGenerator::CanvasPtr AssetGenerator::createCreatureInfoPanel(int boxesAmount) const
  534. {
  535. Point size(438, 187);
  536. auto image = ENGINE->renderHandler().createImage(size, CanvasScalingPolicy::IGNORE);
  537. Canvas canvas = image->getCanvas();
  538. Rect r(4, 40, 102, 132);
  539. canvas.drawColor(r, Colors::BLACK);
  540. canvas.drawBorder(r, Colors::YELLOW);
  541. const ColorRGBA rectangleColor = ColorRGBA(0, 0, 0, 75);
  542. const ColorRGBA rectangleColorRed = ColorRGBA(32, 0, 0, 150);
  543. const ColorRGBA borderColor = ColorRGBA(128, 100, 75);
  544. r = Rect(60, 3, 315, 21);
  545. canvas.drawColorBlended(r, rectangleColor);
  546. canvas.drawBorder(r, borderColor);
  547. for(int i = 0; i < 8; i++)
  548. {
  549. Rect r(114, 30 + i * 19, 24, 20);
  550. canvas.drawColorBlended(r, rectangleColor);
  551. canvas.drawBorder(r, borderColor);
  552. r.x += 23;
  553. r.w = 173;
  554. canvas.drawColorBlended(r, rectangleColor);
  555. canvas.drawBorder(r, borderColor);
  556. }
  557. std::vector<Rect> redRects = {
  558. Rect(319, 30, 45, 45),
  559. Rect(373, 30, 45, 45)
  560. };
  561. std::vector<Rect> darkRects = {};
  562. if(boxesAmount == 3)
  563. {
  564. redRects.push_back(Rect(347, 109, 45, 45));
  565. darkRects.push_back(Rect(347, 156, 45, 19));
  566. }
  567. else if(boxesAmount == 4)
  568. {
  569. redRects.push_back(Rect(319, 109, 45, 45));
  570. redRects.push_back(Rect(373, 109, 45, 45));
  571. darkRects.push_back(Rect(319, 156, 45, 19));
  572. darkRects.push_back(Rect(373, 156, 45, 19));
  573. }
  574. for(auto & rect : darkRects)
  575. {
  576. canvas.drawColorBlended(rect, rectangleColor);
  577. canvas.drawBorder(rect, borderColor);
  578. }
  579. for(auto & rect : redRects)
  580. {
  581. canvas.drawColorBlended(rect, rectangleColorRed);
  582. canvas.drawBorder(rect, borderColor);
  583. }
  584. return image;
  585. }
  586. AssetGenerator::CanvasPtr AssetGenerator::createResourceWindow(CreateResourceWindowType type, int count, PlayerColor color) const
  587. {
  588. assert(count >= 8 && count <= 9);
  589. const std::map<CreateResourceWindowType, ImagePath> files = {
  590. { ARTIFACTS_BUYING, ImagePath::builtin("TPMRKABS") },
  591. { ARTIFACTS_SELLING, ImagePath::builtin("TPMRKASS") },
  592. { MARKET_RESOURCES, ImagePath::builtin("TPMRKRES") },
  593. { FREELANCERS_GUILD, ImagePath::builtin("TPMRKCRS") },
  594. { TRANSFER_RESOURCES, ImagePath::builtin("TPMRKPTS") }
  595. };
  596. auto file = files.at(type);
  597. auto locator = ImageLocator(file, EImageBlitMode::COLORKEY);
  598. std::shared_ptr<IImage> baseImg = ENGINE->renderHandler().loadImage(locator);
  599. baseImg->playerColored(color);
  600. auto image = ENGINE->renderHandler().createImage(baseImg->dimensions(), CanvasScalingPolicy::IGNORE);
  601. Canvas canvas = image->getCanvas();
  602. canvas.draw(baseImg, Point(0, 0));
  603. auto drawBox = [&canvas, &baseImg](bool left, bool one){
  604. if(left)
  605. {
  606. canvas.draw(baseImg, Point(38, 339), Rect(121, 339, 71, 69));
  607. if(!one)
  608. canvas.draw(baseImg, Point(204, 339), Rect(121, 339, 71, 69));
  609. }
  610. else
  611. {
  612. canvas.draw(baseImg, Point(325, 339), Rect(408, 339, 71, 69));
  613. if(!one)
  614. canvas.draw(baseImg, Point(491, 339), Rect(408, 339, 71, 69));
  615. }
  616. };
  617. switch (type)
  618. {
  619. case ARTIFACTS_BUYING:
  620. drawBox(true, count == 8);
  621. break;
  622. case ARTIFACTS_SELLING:
  623. drawBox(false, count == 8);
  624. break;
  625. case MARKET_RESOURCES:
  626. drawBox(true, count == 8);
  627. drawBox(false, count == 8);
  628. break;
  629. case FREELANCERS_GUILD:
  630. drawBox(false, count == 8);
  631. break;
  632. case TRANSFER_RESOURCES:
  633. drawBox(true, count == 8);
  634. break;
  635. }
  636. return image;
  637. }
  638. AssetGenerator::CanvasPtr AssetGenerator::createCreatureInfoPanelElement(CreatureInfoPanelElement element) const
  639. {
  640. std::map<CreatureInfoPanelElement, Point> size {
  641. {BONUS_EFFECTS, Point(438, 59)},
  642. {SPELL_EFFECTS, Point(438, 42)},
  643. {BUTTON_PANEL, Point(438, 43)},
  644. {COMMANDER_BACKGROUND, Point(438, 177)},
  645. {COMMANDER_ABILITIES, Point(438, 59)}
  646. };
  647. auto image = ENGINE->renderHandler().createImage(size[element], CanvasScalingPolicy::IGNORE);
  648. Canvas canvas = image->getCanvas();
  649. const ColorRGBA rectangleColor = ColorRGBA(0, 0, 0, 75);
  650. const ColorRGBA rectangleColorRed = ColorRGBA(32, 0, 0, 150);
  651. const ColorRGBA borderColor = ColorRGBA(128, 100, 75);
  652. switch (element)
  653. {
  654. case BONUS_EFFECTS:
  655. for(int i = 0; i < 2; i++)
  656. {
  657. Rect r(4 + i * 208, 0, 54, 54);
  658. canvas.drawColorBlended(r, rectangleColorRed);
  659. canvas.drawBorder(r, borderColor);
  660. r = Rect(61 + i * 208, 0, 144, 54);
  661. canvas.drawColorBlended(r, rectangleColor);
  662. canvas.drawBorder(r, borderColor);
  663. }
  664. break;
  665. case SPELL_EFFECTS:
  666. for(int i = 0; i < 8; i++)
  667. {
  668. Rect r(6 + i * 54, 2, 48, 36);
  669. canvas.drawColorBlended(r, rectangleColor);
  670. canvas.drawBorder(r, borderColor);
  671. }
  672. break;
  673. case BUTTON_PANEL:
  674. canvas.drawColorBlended(Rect(382, 5, 52, 36), Colors::BLACK);
  675. break;
  676. case COMMANDER_BACKGROUND:
  677. for(int x = 0; x < 3; x++)
  678. {
  679. for(int y = 0; y < 3; y++)
  680. {
  681. Rect r(269 + x * 52, 21 + y * 52, 44, 44);
  682. canvas.drawColorBlended(r, rectangleColorRed);
  683. canvas.drawBorder(r, borderColor);
  684. }
  685. }
  686. for(int x = 0; x < 3; x++)
  687. {
  688. for(int y = 0; y < 2; y++)
  689. {
  690. Rect r(10 + x * 80, 20 + y * 80, 70, 70);
  691. canvas.drawColor(r, Colors::BLACK);
  692. }
  693. }
  694. break;
  695. case COMMANDER_ABILITIES:
  696. for(int i = 0; i < 6; i++)
  697. {
  698. Rect r(37 + i * 63, 2, 54, 54);
  699. canvas.drawColorBlended(r, rectangleColorRed);
  700. canvas.drawBorder(r, borderColor);
  701. }
  702. for(int i = 0; i < 2; i++)
  703. {
  704. Rect r(10 + i * 401, 6, 22, 46);
  705. canvas.drawColor(r, Colors::BLACK);
  706. }
  707. break;
  708. }
  709. return image;
  710. }
  711. AssetGenerator::CanvasPtr AssetGenerator::createQuestWindow() const
  712. {
  713. auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"), EImageBlitMode::OPAQUE);
  714. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  715. Point size(612, 438);
  716. auto image = ENGINE->renderHandler().createImage(size, CanvasScalingPolicy::IGNORE);
  717. Canvas canvas = image->getCanvas();
  718. for (int y = 0; y < size.y; y += img->height())
  719. for (int x = 0; x < size.x; x += img->width())
  720. canvas.draw(img, Point(x, y), Rect(0, 0, std::min(img->width(), size.x - x), std::min(img->height(), size.y - y)));
  721. Rect r(11, 11, 171, 171);
  722. canvas.drawColor(r, Colors::BLACK);
  723. canvas.drawBorder(r, Colors::YELLOW);
  724. const ColorRGBA rectangleColor = ColorRGBA(0, 0, 0, 75);
  725. const ColorRGBA borderColor = ColorRGBA(128, 100, 75);
  726. for(int i = 0; i < 6; i++)
  727. {
  728. Rect r(11, 194 + i * 32, 155, 33);
  729. canvas.drawColorBlended(r, rectangleColor);
  730. canvas.drawBorder(r, borderColor);
  731. }
  732. r = Rect(165, 194, 18, 193);
  733. canvas.drawColor(r, Colors::BLACK);
  734. canvas.drawBorder(r, borderColor);
  735. r = Rect(193, 11, 408, 376);
  736. canvas.drawColorBlended(r, rectangleColor);
  737. canvas.drawBorder(r, borderColor);
  738. return image;
  739. }
  740. AssetGenerator::AnimationLayoutMap AssetGenerator::createGSPButtonClear()
  741. {
  742. auto baseImg = ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("GSPBUTT"), EImageBlitMode::OPAQUE);
  743. auto overlayImg = ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("GSPBUT2"), EImageBlitMode::OPAQUE);
  744. AnimationLayoutMap layout;
  745. for(int i = 0; i < 4; i++)
  746. {
  747. ImagePath spriteName = ImagePath::builtin("GSPButtonClear" + std::to_string(i) + ".png");
  748. imageFiles[spriteName] = [baseImg, overlayImg, i](){
  749. auto newImg = ENGINE->renderHandler().createImage(baseImg->getImage(i)->dimensions(), CanvasScalingPolicy::IGNORE);
  750. auto canvas = newImg->getCanvas();
  751. canvas.draw(baseImg->getImage(i), Point(0, 0));
  752. canvas.draw(overlayImg->getImage(i), Point(0, 0), Rect(0, 0, 20, 20));
  753. return newImg;
  754. };
  755. layout[0].push_back(ImageLocator(spriteName, EImageBlitMode::SIMPLE));
  756. }
  757. return layout;
  758. }
  759. AssetGenerator::CanvasPtr AssetGenerator::createGateListColored(PlayerColor color, PlayerColor backColor) const
  760. {
  761. auto locator = ImageLocator(ImagePath::builtin("TpGate"), EImageBlitMode::COLORKEY);
  762. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  763. img->playerColored(color);
  764. std::shared_ptr<IImage> imgColored = ENGINE->renderHandler().loadImage(locator);
  765. static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = getColorFilters();
  766. imgColored->adjustPalette(filters[backColor.getNum()], 0);
  767. auto image = ENGINE->renderHandler().createImage(img->dimensions(), CanvasScalingPolicy::IGNORE);
  768. Canvas canvas = image->getCanvas();
  769. canvas.draw(imgColored, Point(0, 0));
  770. std::vector<Rect> keepOriginalRects = {
  771. Rect(0, 0, 14, 393),
  772. Rect(293, 0, 13, 393),
  773. Rect(0, 393, 8, 76),
  774. Rect(299, 393, 6, 76),
  775. Rect(0, 0, 306, 16),
  776. Rect(0, 383, 306, 10),
  777. Rect(0, 441, 306, 2),
  778. Rect(0, 462, 306, 7),
  779. // Edges
  780. Rect(14, 15, 2, 5),
  781. Rect(16, 15, 3, 2),
  782. Rect(16, 17, 1, 1),
  783. Rect(14, 379, 3, 4),
  784. Rect(16, 381, 2, 2),
  785. Rect(16, 380, 1, 1),
  786. Rect(289, 16, 2, 2),
  787. Rect(291, 16, 2, 4),
  788. Rect(289, 381, 2, 2),
  789. Rect(291, 379, 2, 4)
  790. };
  791. for(auto & rect : keepOriginalRects)
  792. canvas.draw(img, Point(rect.x, rect.y), rect);
  793. std::vector<Rect> blackRect = {
  794. Rect(14, 401, 66, 32),
  795. Rect(227, 401, 66, 32)
  796. };
  797. for(auto & rect : blackRect)
  798. canvas.drawBorder(rect, Colors::BLACK);
  799. return image;
  800. }
  801. AssetGenerator::CanvasPtr AssetGenerator::createHeroSlotsColored(PlayerColor backColor) const
  802. {
  803. auto locator = ImageLocator(AnimationPath::builtin("OVSLOT"), 4, 0, EImageBlitMode::COLORKEY);
  804. std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
  805. static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = getColorFilters();
  806. img->adjustPalette(filters[backColor.getNum()], 0);
  807. auto image = ENGINE->renderHandler().createImage(Point(260, 150), CanvasScalingPolicy::IGNORE);
  808. Canvas canvas = image->getCanvas();
  809. canvas.draw(img, Point(0, 0), Rect(3, 4, 253, 107));
  810. for(int i = 0; i<7; i++)
  811. canvas.draw(img, Point(1 + i * 36, 108), Rect(76, 57, 35, 17));
  812. return image;
  813. }