AssetGenerator.cpp 41 KB

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