mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-19 21:10:12 +02:00
Merge pull request #5352 from IvanSavenko/assets_generation
[1.6.5] In-memory assets generation
This commit is contained in:
commit
c5a75b20ad
@ -18,7 +18,6 @@
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/WindowHandler.h"
|
||||
#include "render/IRenderHandler.h"
|
||||
#include "render/AssetGenerator.h"
|
||||
#include "ClientNetPackVisitors.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/gameState/CGameState.h"
|
||||
@ -510,7 +509,7 @@ void ClientCommandManager::handleVsLog(std::istringstream & singleWordBuffer)
|
||||
|
||||
void ClientCommandManager::handleGenerateAssets()
|
||||
{
|
||||
AssetGenerator::generateAll();
|
||||
GH.renderHandler().exportGeneratedAssets();
|
||||
printCommandMessage("All assets generated");
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "../render/IImage.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../CMT.h"
|
||||
#include "../PlayerLocalState.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
@ -65,8 +64,6 @@ AdventureMapInterface::AdventureMapInterface():
|
||||
pos.w = GH.screenDimensions().x;
|
||||
pos.h = GH.screenDimensions().y;
|
||||
|
||||
AssetGenerator::createPaletteShiftedSprites();
|
||||
|
||||
shortcuts = std::make_shared<AdventureMapShortcuts>(*this);
|
||||
|
||||
widget = std::make_shared<AdventureMapWidget>(shortcuts);
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/WindowHandler.h"
|
||||
#include "../media/ISoundPlayer.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../render/Colors.h"
|
||||
#include "../render/Canvas.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
@ -80,7 +79,6 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
|
||||
stackToActivate(nullptr),
|
||||
animIDhelper(0)
|
||||
{
|
||||
AssetGenerator::createCombatUnitNumberWindow();
|
||||
//preparing graphics for displaying amounts of creatures
|
||||
amountNormal = GH.renderHandler().loadImage(ImagePath::builtin("combatUnitNumberWindowDefault"), EImageBlitMode::COLORKEY);
|
||||
amountPositive = GH.renderHandler().loadImage(ImagePath::builtin("combatUnitNumberWindowPositive"), EImageBlitMode::COLORKEY);
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../CServerHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../../lib/texts/CGeneralTextHandler.h"
|
||||
@ -69,8 +68,6 @@ std::vector<SimturnsInfo> OptionsTabBase::getSimturnsPresets() const
|
||||
|
||||
OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
|
||||
{
|
||||
AssetGenerator::createAdventureOptionsCleanBackground();
|
||||
|
||||
recActions = 0;
|
||||
|
||||
auto setTimerPresetCallback = [this](int index){
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "../widgets/VideoWidget.h"
|
||||
#include "../windows/InfoWindows.h"
|
||||
#include "../CServerHandler.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
@ -428,9 +427,6 @@ void CMainMenu::openCampaignScreen(std::string name)
|
||||
{
|
||||
auto const & config = CMainMenuConfig::get().getCampaigns();
|
||||
|
||||
AssetGenerator::createCampaignBackground();
|
||||
AssetGenerator::createChroniclesCampaignImages();
|
||||
|
||||
if(!vstd::contains(config.Struct(), name))
|
||||
{
|
||||
logGlobal->error("Unknown campaign set: %s", name);
|
||||
|
@ -29,36 +29,60 @@
|
||||
#include "../lib/RoadHandler.h"
|
||||
#include "../lib/TerrainHandler.h"
|
||||
|
||||
void AssetGenerator::clear()
|
||||
AssetGenerator::AssetGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
void AssetGenerator::initialize()
|
||||
{
|
||||
// clear to avoid non updated sprites after mod change (if base imnages are used)
|
||||
if(boost::filesystem::is_directory(VCMIDirs::get().userDataPath() / "Generated"))
|
||||
boost::filesystem::remove_all(VCMIDirs::get().userDataPath() / "Generated");
|
||||
}
|
||||
|
||||
void AssetGenerator::generateAll()
|
||||
{
|
||||
createBigSpellBook();
|
||||
createAdventureOptionsCleanBackground();
|
||||
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
createPlayerColoredBackground(PlayerColor(i));
|
||||
createCombatUnitNumberWindow();
|
||||
createCampaignBackground();
|
||||
createChroniclesCampaignImages();
|
||||
imageFiles[ImagePath::builtin("AdventureOptionsBackgroundClear.png")] = [this](){ return createAdventureOptionsCleanBackground();};
|
||||
imageFiles[ImagePath::builtin("SpellBookLarge.png")] = [this](){ return createBigSpellBook();};
|
||||
|
||||
imageFiles[ImagePath::builtin("combatUnitNumberWindowDefault.png")] = [this](){ return createCombatUnitNumberWindow(0.6f, 0.2f, 1.0f);};
|
||||
imageFiles[ImagePath::builtin("combatUnitNumberWindowNeutral.png")] = [this](){ return createCombatUnitNumberWindow(1.0f, 1.0f, 2.0f);};
|
||||
imageFiles[ImagePath::builtin("combatUnitNumberWindowPositive.png")] = [this](){ return createCombatUnitNumberWindow(0.2f, 1.0f, 0.2f);};
|
||||
imageFiles[ImagePath::builtin("combatUnitNumberWindowNegative.png")] = [this](){ return createCombatUnitNumberWindow(1.0f, 0.2f, 0.2f);};
|
||||
|
||||
imageFiles[ImagePath::builtin("CampaignBackground8.png")] = [this](){ return createCampaignBackground();};
|
||||
|
||||
for (PlayerColor color(0); color < PlayerColor::PLAYER_LIMIT; ++color)
|
||||
imageFiles[ImagePath::builtin("DialogBoxBackground_" + color.toString())] = [this, color](){ return createPlayerColoredBackground(color);};
|
||||
|
||||
for(int i = 1; i < 9; i++)
|
||||
imageFiles[ImagePath::builtin("CampaignHc" + std::to_string(i) + "Image.png")] = [this, i](){ return createChroniclesCampaignImages(i);};
|
||||
|
||||
createPaletteShiftedSprites();
|
||||
}
|
||||
|
||||
void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
std::shared_ptr<ISharedImage> AssetGenerator::generateImage(const ImagePath & image)
|
||||
{
|
||||
std::string filename = "data/AdventureOptionsBackgroundClear.png";
|
||||
if (imageFiles.count(image))
|
||||
return imageFiles.at(image)()->toSharedImage(); // TODO: cache?
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
|
||||
return;
|
||||
std::map<ImagePath, std::shared_ptr<ISharedImage>> AssetGenerator::generateAllImages()
|
||||
{
|
||||
std::map<ImagePath, std::shared_ptr<ISharedImage>> result;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filename))
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
for (const auto & entry : imageFiles)
|
||||
result[entry.first] = entry.second()->toSharedImage();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<AnimationPath, AssetGenerator::AnimationLayoutMap> AssetGenerator::generateAllAnimations()
|
||||
{
|
||||
return animationFiles;
|
||||
}
|
||||
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
{
|
||||
auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
@ -74,20 +98,11 @@ void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
canvas.draw(img, Point(53, 567), Rect(53, 520, 339, 3));
|
||||
canvas.draw(img, Point(53, 520), Rect(53, 264, 339, 47));
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createBigSpellBook()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createBigSpellBook()
|
||||
{
|
||||
std::string filename = "data/SpellBookLarge.png";
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filename))
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("SpelBack"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
@ -135,21 +150,11 @@ void AssetGenerator::createBigSpellBook()
|
||||
canvas.draw(img, Point(575, 465), Rect(417, 406, 37, 45));
|
||||
canvas.draw(img, Point(667, 465), Rect(478, 406, 37, 47));
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
||||
{
|
||||
std::string filename = "data/DialogBoxBackground_" + player.toString() + ".png";
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filename))
|
||||
return;
|
||||
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator);
|
||||
@ -169,71 +174,44 @@ void AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
||||
|
||||
assert(player.isValidPlayer());
|
||||
if (!player.isValidPlayer())
|
||||
{
|
||||
logGlobal->error("Unable to colorize to invalid player color %d!", player.getNum());
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error("Unable to colorize to invalid player color" + std::to_string(player.getNum()));
|
||||
|
||||
texture->adjustPalette(filters[player.getNum()], 0);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
|
||||
auto image = GH.renderHandler().createImage(texture->dimensions(), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(texture, Point(0,0));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createCombatUnitNumberWindow()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createCombatUnitNumberWindow(float multR, float multG, float multB)
|
||||
{
|
||||
std::string filenameToSave = "data/combatUnitNumberWindow";
|
||||
|
||||
ResourcePath savePathDefault(filenameToSave + "Default.png", EResType::IMAGE);
|
||||
ResourcePath savePathNeutral(filenameToSave + "Neutral.png", EResType::IMAGE);
|
||||
ResourcePath savePathPositive(filenameToSave + "Positive.png", EResType::IMAGE);
|
||||
ResourcePath savePathNegative(filenameToSave + "Negative.png", EResType::IMAGE);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(savePathDefault)) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(savePathDefault.getOriginalName() + ".png") ||
|
||||
!CResourceHandler::get("local")->createResource(savePathNeutral.getOriginalName() + ".png") ||
|
||||
!CResourceHandler::get("local")->createResource(savePathPositive.getOriginalName() + ".png") ||
|
||||
!CResourceHandler::get("local")->createResource(savePathNegative.getOriginalName() + ".png"))
|
||||
return;
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"), EImageBlitMode::OPAQUE);
|
||||
locator.layer = EImageBlitMode::OPAQUE;
|
||||
|
||||
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator);
|
||||
|
||||
static const auto shifterNormal = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.6f, 0.2f, 1.0f );
|
||||
static const auto shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );
|
||||
static const auto shifterNegative = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 0.2f, 0.2f );
|
||||
static const auto shifterNeutral = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 1.0f, 0.2f );
|
||||
const auto shifter= ColorFilter::genRangeShifter(0.f, 0.f, 0.f, multR, multG, multB);
|
||||
|
||||
// do not change border color
|
||||
static const int32_t ignoredMask = 1 << 26;
|
||||
|
||||
texture->adjustPalette(shifterNormal, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathDefault));
|
||||
texture->adjustPalette(shifterPositive, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathPositive));
|
||||
texture->adjustPalette(shifterNegative, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathNegative));
|
||||
texture->adjustPalette(shifterNeutral, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathNeutral));
|
||||
texture->adjustPalette(shifter, ignoredMask);
|
||||
|
||||
auto image = GH.renderHandler().createImage(texture->dimensions(), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(texture, Point(0,0));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createCampaignBackground()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createCampaignBackground()
|
||||
{
|
||||
std::string filename = "data/CampaignBackground8.png";
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filename))
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||
auto image = GH.renderHandler().createImage(Point(200, 116), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
|
||||
canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
|
||||
@ -264,171 +242,112 @@ void AssetGenerator::createCampaignBackground()
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createChroniclesCampaignImages()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createChroniclesCampaignImages(int chronicle)
|
||||
{
|
||||
for(int i = 1; i < 9; i++)
|
||||
auto imgPathBg = ImagePath::builtin("data/chronicles_" + std::to_string(chronicle) + "/GamSelBk");
|
||||
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
|
||||
std::array sourceRect = {
|
||||
Rect(149, 144, 200, 116),
|
||||
Rect(156, 150, 200, 116),
|
||||
Rect(171, 153, 200, 116),
|
||||
Rect(35, 358, 200, 116),
|
||||
Rect(216, 248, 200, 116),
|
||||
Rect(58, 234, 200, 116),
|
||||
Rect(184, 219, 200, 116),
|
||||
Rect(268, 210, 200, 116),
|
||||
};
|
||||
|
||||
canvas.draw(img, Point(0, 0), sourceRect.at(chronicle-1));
|
||||
|
||||
if (chronicle == 8)
|
||||
{
|
||||
std::string filename = "data/CampaignHc" + std::to_string(i) + "Image.png";
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
|
||||
continue;
|
||||
|
||||
auto imgPathBg = ImagePath::builtin("data/chronicles_" + std::to_string(i) + "/GamSelBk");
|
||||
if(!CResourceHandler::get()->existsResource(imgPathBg)) // Chronicle episode not installed
|
||||
continue;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filename))
|
||||
continue;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
canvas.draw(img, Point(0, 0), Rect(149, 144, 200, 116));
|
||||
break;
|
||||
case 2:
|
||||
canvas.draw(img, Point(0, 0), Rect(156, 150, 200, 116));
|
||||
break;
|
||||
case 3:
|
||||
canvas.draw(img, Point(0, 0), Rect(171, 153, 200, 116));
|
||||
break;
|
||||
case 4:
|
||||
canvas.draw(img, Point(0, 0), Rect(35, 358, 200, 116));
|
||||
break;
|
||||
case 5:
|
||||
canvas.draw(img, Point(0, 0), Rect(216, 248, 200, 116));
|
||||
break;
|
||||
case 6:
|
||||
canvas.draw(img, Point(0, 0), Rect(58, 234, 200, 116));
|
||||
break;
|
||||
case 7:
|
||||
canvas.draw(img, Point(0, 0), Rect(184, 219, 200, 116));
|
||||
break;
|
||||
case 8:
|
||||
canvas.draw(img, Point(0, 0), Rect(268, 210, 200, 116));
|
||||
|
||||
//skull
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"), EImageBlitMode::OPAQUE);
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
canvas.draw(imgSkull, Point(162, 94), Rect(162, 94, 41, 22));
|
||||
canvas.draw(img, Point(162, 94), Rect(424, 304, 14, 4));
|
||||
canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
|
||||
canvas.draw(img, Point(158, 102), Rect(424, 312, 10, 4));
|
||||
canvas.draw(img, Point(154, 106), Rect(424, 316, 10, 4));
|
||||
break;
|
||||
}
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
//skull
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"), EImageBlitMode::OPAQUE);
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
canvas.draw(imgSkull, Point(162, 94), Rect(162, 94, 41, 22));
|
||||
canvas.draw(img, Point(162, 94), Rect(424, 304, 14, 4));
|
||||
canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
|
||||
canvas.draw(img, Point(158, 102), Rect(424, 312, 10, 4));
|
||||
canvas.draw(img, Point(154, 106), Rect(424, 316, 10, 4));
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createPaletteShiftedSprites()
|
||||
{
|
||||
std::vector<std::string> tiles;
|
||||
std::vector<std::vector<std::variant<TerrainPaletteAnimation, RiverPaletteAnimation>>> paletteAnimations;
|
||||
for(auto entity : VLC->terrainTypeHandler->objects)
|
||||
{
|
||||
if(entity->paletteAnimation.size())
|
||||
{
|
||||
tiles.push_back(entity->tilesFilename.getName());
|
||||
std::vector<std::variant<TerrainPaletteAnimation, RiverPaletteAnimation>> tmpAnim;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
tmpAnim.push_back(animEntity);
|
||||
paletteAnimations.push_back(tmpAnim);
|
||||
}
|
||||
if(entity->paletteAnimation.empty())
|
||||
continue;
|
||||
|
||||
std::vector<PaletteAnimation> paletteShifts;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
paletteShifts.push_back({animEntity.start, animEntity.length});
|
||||
|
||||
generatePaletteShiftedAnimation(entity->tilesFilename, paletteShifts);
|
||||
|
||||
}
|
||||
for(auto entity : VLC->riverTypeHandler->objects)
|
||||
{
|
||||
if(entity->paletteAnimation.size())
|
||||
{
|
||||
tiles.push_back(entity->tilesFilename.getName());
|
||||
std::vector<std::variant<TerrainPaletteAnimation, RiverPaletteAnimation>> tmpAnim;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
tmpAnim.push_back(animEntity);
|
||||
paletteAnimations.push_back(tmpAnim);
|
||||
}
|
||||
}
|
||||
if(entity->paletteAnimation.empty())
|
||||
continue;
|
||||
|
||||
for(int i = 0; i < tiles.size(); i++)
|
||||
{
|
||||
auto sprite = tiles[i];
|
||||
std::vector<PaletteAnimation> paletteShifts;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
paletteShifts.push_back({animEntity.start, animEntity.length});
|
||||
|
||||
JsonNode config;
|
||||
config["basepath"].String() = sprite + "_Shifted/";
|
||||
config["images"].Vector();
|
||||
|
||||
auto filename = AnimationPath::builtin(sprite).addPrefix("SPRITES/");
|
||||
auto filenameNew = AnimationPath::builtin(sprite + "_Shifted").addPrefix("SPRITES/");
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filenameNew.getName(), EResType::JSON))) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
auto anim = GH.renderHandler().loadAnimation(filename, EImageBlitMode::COLORKEY);
|
||||
for(int j = 0; j < anim->size(); j++)
|
||||
{
|
||||
int maxLen = 1;
|
||||
for(int k = 0; k < paletteAnimations[i].size(); k++)
|
||||
{
|
||||
auto element = paletteAnimations[i][k];
|
||||
if(std::holds_alternative<TerrainPaletteAnimation>(element))
|
||||
maxLen = std::lcm(maxLen, std::get<TerrainPaletteAnimation>(element).length);
|
||||
else
|
||||
maxLen = std::lcm(maxLen, std::get<RiverPaletteAnimation>(element).length);
|
||||
}
|
||||
for(int l = 0; l < maxLen; l++)
|
||||
{
|
||||
std::string spriteName = sprite + boost::str(boost::format("%02d") % j) + "_" + std::to_string(l) + ".png";
|
||||
std::string filenameNewImg = "sprites/" + sprite + "_Shifted" + "/" + spriteName;
|
||||
ResourcePath savePath(filenameNewImg, EResType::IMAGE);
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filenameNewImg))
|
||||
return;
|
||||
|
||||
auto imgLoc = anim->getImageLocator(j, 0);
|
||||
auto img = GH.renderHandler().loadImage(imgLoc);
|
||||
for(int k = 0; k < paletteAnimations[i].size(); k++)
|
||||
{
|
||||
auto element = paletteAnimations[i][k];
|
||||
if(std::holds_alternative<TerrainPaletteAnimation>(element))
|
||||
{
|
||||
auto tmp = std::get<TerrainPaletteAnimation>(element);
|
||||
img->shiftPalette(tmp.start, tmp.length, l % tmp.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = std::get<RiverPaletteAnimation>(element);
|
||||
img->shiftPalette(tmp.start, tmp.length, l % tmp.length);
|
||||
}
|
||||
}
|
||||
|
||||
auto image = GH.renderHandler().createImage(Point(32, 32), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
|
||||
JsonNode node(JsonMap{
|
||||
{ "group", JsonNode(l) },
|
||||
{ "frame", JsonNode(j) },
|
||||
{ "file", JsonNode(spriteName) }
|
||||
});
|
||||
config["images"].Vector().push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
ResourcePath savePath(filenameNew.getOriginalName(), EResType::JSON);
|
||||
if(!CResourceHandler::get("local")->createResource(filenameNew.getOriginalName() + ".json"))
|
||||
return;
|
||||
|
||||
std::fstream file(CResourceHandler::get("local")->getResourceName(savePath)->c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
file << config.toString();
|
||||
generatePaletteShiftedAnimation(entity->tilesFilename, paletteShifts);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetGenerator::generatePaletteShiftedAnimation(const AnimationPath & sprite, const std::vector<PaletteAnimation> & paletteAnimations)
|
||||
{
|
||||
AnimationLayoutMap layout;
|
||||
|
||||
auto animation = GH.renderHandler().loadAnimation(sprite, EImageBlitMode::COLORKEY);
|
||||
|
||||
int paletteTransformLength = 1;
|
||||
for (const auto & transform : paletteAnimations)
|
||||
paletteTransformLength = std::lcm(paletteTransformLength, transform.length);
|
||||
|
||||
for(int tileIndex = 0; tileIndex < animation->size(); tileIndex++)
|
||||
{
|
||||
for(int paletteIndex = 0; paletteIndex < paletteTransformLength; paletteIndex++)
|
||||
{
|
||||
ImagePath spriteName = ImagePath::builtin(sprite.getName() + boost::str(boost::format("%02d") % tileIndex) + "_" + std::to_string(paletteIndex) + ".png");
|
||||
layout[paletteIndex].push_back(ImageLocator(spriteName, EImageBlitMode::SIMPLE));
|
||||
|
||||
imageFiles[spriteName] = [=](){ return createPaletteShiftedImage(sprite, paletteAnimations, tileIndex, paletteIndex);};
|
||||
}
|
||||
}
|
||||
|
||||
AnimationPath shiftedPath = AnimationPath::builtin("SPRITES/" + sprite.getName() + "_SHIFTED");
|
||||
animationFiles[shiftedPath] = layout;
|
||||
}
|
||||
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createPaletteShiftedImage(const AnimationPath & source, const std::vector<PaletteAnimation> & palette, int frameIndex, int paletteShiftCounter)
|
||||
{
|
||||
auto animation = GH.renderHandler().loadAnimation(source, EImageBlitMode::COLORKEY);
|
||||
|
||||
auto imgLoc = animation->getImageLocator(frameIndex, 0);
|
||||
auto img = GH.renderHandler().loadImage(imgLoc);
|
||||
|
||||
for(const auto & element : palette)
|
||||
img->shiftPalette(element.start, element.length, paletteShiftCounter % element.length);
|
||||
|
||||
auto image = GH.renderHandler().createImage(Point(32, 32), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
|
||||
|
||||
return image;
|
||||
|
||||
}
|
||||
|
@ -9,20 +9,53 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ImageLocator.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class PlayerColor;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class ISharedImage;
|
||||
class CanvasImage;
|
||||
|
||||
class AssetGenerator
|
||||
{
|
||||
public:
|
||||
static void clear();
|
||||
static void generateAll();
|
||||
static void createAdventureOptionsCleanBackground();
|
||||
static void createBigSpellBook();
|
||||
static void createPlayerColoredBackground(const PlayerColor & player);
|
||||
static void createCombatUnitNumberWindow();
|
||||
static void createCampaignBackground();
|
||||
static void createChroniclesCampaignImages();
|
||||
static void createPaletteShiftedSprites();
|
||||
using AnimationLayoutMap = std::map<size_t, std::vector<ImageLocator>>;
|
||||
using CanvasPtr = std::shared_ptr<CanvasImage>;
|
||||
|
||||
AssetGenerator();
|
||||
|
||||
void initialize();
|
||||
|
||||
std::shared_ptr<ISharedImage> generateImage(const ImagePath & image);
|
||||
|
||||
std::map<ImagePath, std::shared_ptr<ISharedImage>> generateAllImages();
|
||||
std::map<AnimationPath, AnimationLayoutMap> generateAllAnimations();
|
||||
|
||||
private:
|
||||
using ImageGenerationFunctor = std::function<CanvasPtr()>;
|
||||
|
||||
struct PaletteAnimation
|
||||
{
|
||||
/// index of first color to cycle
|
||||
int32_t start;
|
||||
/// total numbers of colors to cycle
|
||||
int32_t length;
|
||||
};
|
||||
|
||||
std::map<ImagePath, ImageGenerationFunctor> imageFiles;
|
||||
std::map<AnimationPath, AnimationLayoutMap> animationFiles;
|
||||
|
||||
CanvasPtr createAdventureOptionsCleanBackground();
|
||||
CanvasPtr createBigSpellBook();
|
||||
CanvasPtr createPlayerColoredBackground(const PlayerColor & player);
|
||||
CanvasPtr createCombatUnitNumberWindow(float multR, float multG, float multB);
|
||||
CanvasPtr createCampaignBackground();
|
||||
CanvasPtr createChroniclesCampaignImages(int chronicle);
|
||||
CanvasPtr createPaletteShiftedImage(const AnimationPath & source, const std::vector<PaletteAnimation> & animation, int frameIndex, int paletteShiftCounter);
|
||||
|
||||
void createPaletteShiftedSprites();
|
||||
void generatePaletteShiftedAnimation(const AnimationPath & source, const std::vector<PaletteAnimation> & animation);
|
||||
|
||||
};
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../renderSDL/SDL_Extensions.h"
|
||||
#include "../renderSDL/SDLImageScaler.h"
|
||||
#include "../renderSDL/SDLImage.h"
|
||||
|
||||
#include <SDL_image.h>
|
||||
#include <SDL_surface.h>
|
||||
@ -61,3 +62,8 @@ Point CanvasImage::dimensions() const
|
||||
{
|
||||
return {surface->w, surface->h};
|
||||
}
|
||||
|
||||
std::shared_ptr<ISharedImage> CanvasImage::toSharedImage()
|
||||
{
|
||||
return std::make_shared<SDLImageShared>(surface);
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ public:
|
||||
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override{};
|
||||
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override{};
|
||||
|
||||
std::shared_ptr<ISharedImage> toSharedImage();
|
||||
|
||||
private:
|
||||
SDL_Surface * surface;
|
||||
CanvasScalingPolicy scalingPolicy;
|
||||
|
@ -50,4 +50,6 @@ public:
|
||||
|
||||
/// Returns font with specified identifer
|
||||
virtual std::shared_ptr<const IFont> loadFont(EFonts font) = 0;
|
||||
|
||||
virtual void exportGeneratedAssets() = 0;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../render/CAnimation.h"
|
||||
#include "../render/CanvasImage.h"
|
||||
#include "../render/CDefFile.h"
|
||||
@ -43,6 +44,13 @@
|
||||
#include <vcmi/SkillService.h>
|
||||
#include <vcmi/spells/Service.h>
|
||||
|
||||
RenderHandler::RenderHandler()
|
||||
:assetGenerator(std::make_unique<AssetGenerator>())
|
||||
{
|
||||
}
|
||||
|
||||
RenderHandler::~RenderHandler() = default;
|
||||
|
||||
std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath & path)
|
||||
{
|
||||
AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/");
|
||||
@ -201,12 +209,28 @@ std::shared_ptr<ScalableImageShared> RenderHandler::loadImageImpl(const ImageLoc
|
||||
return scaledImage;
|
||||
}
|
||||
|
||||
std::shared_ptr<SDLImageShared> RenderHandler::loadImageFromFileUncached(const ImageLocator & locator)
|
||||
std::shared_ptr<ISharedImage> RenderHandler::loadImageFromFileUncached(const ImageLocator & locator)
|
||||
{
|
||||
if(locator.image)
|
||||
{
|
||||
// TODO: create EmptySharedImage class that will be instantiated if image does not exists or fails to load
|
||||
return std::make_shared<SDLImageShared>(*locator.image);
|
||||
auto imagePath = *locator.image;
|
||||
auto imagePathSprites = imagePath.addPrefix("SPRITES/");
|
||||
auto imagePathData = imagePath.addPrefix("DATA/");
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePathSprites))
|
||||
return std::make_shared<SDLImageShared>(imagePathSprites);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePathData))
|
||||
return std::make_shared<SDLImageShared>(imagePathData);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePath))
|
||||
return std::make_shared<SDLImageShared>(imagePath);
|
||||
|
||||
auto generated = assetGenerator->generateImage(imagePath);
|
||||
if (generated)
|
||||
return generated;
|
||||
|
||||
return std::make_shared<SDLImageShared>(ImagePath::builtin("DEFAULT"));
|
||||
}
|
||||
|
||||
if(locator.defFile)
|
||||
@ -423,6 +447,10 @@ static void detectOverlappingBuildings(RenderHandler * renderHandler, const Fact
|
||||
|
||||
void RenderHandler::onLibraryLoadingFinished(const Services * services)
|
||||
{
|
||||
assert(animationLayouts.empty());
|
||||
assetGenerator->initialize();
|
||||
animationLayouts = assetGenerator->generateAllAnimations();
|
||||
|
||||
addImageListEntries(services->creatures());
|
||||
addImageListEntries(services->heroTypes());
|
||||
addImageListEntries(services->artifacts());
|
||||
@ -469,3 +497,9 @@ std::shared_ptr<const IFont> RenderHandler::loadFont(EFonts font)
|
||||
fonts[font] = loadedFont;
|
||||
return loadedFont;
|
||||
}
|
||||
|
||||
void RenderHandler::exportGeneratedAssets()
|
||||
{
|
||||
for (const auto & entry : assetGenerator->generateAllImages())
|
||||
entry.second->exportBitmap(VCMIDirs::get().userDataPath() / "Generated" / (entry.first.getOriginalName() + ".png"), nullptr);
|
||||
}
|
||||
|
@ -18,8 +18,9 @@ VCMI_LIB_NAMESPACE_END
|
||||
class CDefFile;
|
||||
class SDLImageShared;
|
||||
class ScalableImageShared;
|
||||
class AssetGenerator;
|
||||
|
||||
class RenderHandler : public IRenderHandler
|
||||
class RenderHandler final : public IRenderHandler
|
||||
{
|
||||
using AnimationLayoutMap = std::map<size_t, std::vector<ImageLocator>>;
|
||||
|
||||
@ -27,6 +28,7 @@ class RenderHandler : public IRenderHandler
|
||||
std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
|
||||
std::map<SharedImageLocator, std::shared_ptr<ScalableImageShared>> imageFiles;
|
||||
std::map<EFonts, std::shared_ptr<const IFont>> fonts;
|
||||
std::unique_ptr<AssetGenerator> assetGenerator;
|
||||
|
||||
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
|
||||
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path, int scalingFactor, EImageBlitMode mode);
|
||||
@ -38,13 +40,15 @@ class RenderHandler : public IRenderHandler
|
||||
|
||||
std::shared_ptr<ScalableImageShared> loadImageImpl(const ImageLocator & config);
|
||||
|
||||
std::shared_ptr<SDLImageShared> loadImageFromFileUncached(const ImageLocator & locator);
|
||||
std::shared_ptr<ISharedImage> loadImageFromFileUncached(const ImageLocator & locator);
|
||||
|
||||
ImageLocator getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group, int scaling, EImageBlitMode mode);
|
||||
|
||||
int getScalingFactor() const;
|
||||
|
||||
public:
|
||||
RenderHandler();
|
||||
~RenderHandler();
|
||||
|
||||
// IRenderHandler implementation
|
||||
void onLibraryLoadingFinished(const Services * services) override;
|
||||
@ -61,4 +65,6 @@ public:
|
||||
|
||||
/// Returns font with specified identifer
|
||||
std::shared_ptr<const IFont> loadFont(EFonts font) override;
|
||||
|
||||
void exportGeneratedAssets() override;
|
||||
};
|
||||
|
@ -306,6 +306,10 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size,
|
||||
|
||||
void SDLImageShared::exportBitmap(const boost::filesystem::path& path, SDL_Palette * palette) const
|
||||
{
|
||||
auto directory = path;
|
||||
directory.remove_filename();
|
||||
boost::filesystem::create_directories(directory);
|
||||
|
||||
assert(upscalingInProgress == false);
|
||||
if (!surf)
|
||||
return;
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "MiscWidgets.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../render/IImage.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
#include "../render/CAnimation.h"
|
||||
@ -184,8 +183,6 @@ FilledTexturePlayerColored::FilledTexturePlayerColored(Rect position)
|
||||
|
||||
void FilledTexturePlayerColored::setPlayerColor(PlayerColor player)
|
||||
{
|
||||
AssetGenerator::createPlayerColoredBackground(player);
|
||||
|
||||
ImagePath imagePath = ImagePath::builtin("DialogBoxBackground_" + player.toString() + ".bmp");
|
||||
|
||||
texture = GH.renderHandler().loadImage(imagePath, EImageBlitMode::COLORKEY);
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "../widgets/Buttons.h"
|
||||
#include "../widgets/VideoWidget.h"
|
||||
#include "../adventureMap/AdventureMapInterface.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
@ -118,7 +117,6 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
||||
|
||||
if(isBigSpellbook)
|
||||
{
|
||||
AssetGenerator::createBigSpellBook();
|
||||
background = std::make_shared<CPicture>(ImagePath::builtin("SpellBookLarge"), 0, 0);
|
||||
updateShadow();
|
||||
}
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "../client/media/CMusicHandler.h"
|
||||
#include "../client/media/CSoundHandler.h"
|
||||
#include "../client/media/CVideoHandler.h"
|
||||
#include "../client/render/AssetGenerator.h"
|
||||
#include "../client/render/Graphics.h"
|
||||
#include "../client/render/IRenderHandler.h"
|
||||
#include "../client/render/IScreenHandler.h"
|
||||
@ -235,8 +234,6 @@ int main(int argc, char * argv[])
|
||||
logGlobal->info("Creating console and configuring logger: %d ms", pomtime.getDiff());
|
||||
logGlobal->info("The log file will be saved to %s", logPath);
|
||||
|
||||
AssetGenerator::clear();
|
||||
|
||||
// Init filesystem and settings
|
||||
try
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user