mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
Merge pull request #5008 from Laserlicht/sprites_test
Tile animation for rivers with xbrz
This commit is contained in:
commit
fe51194e22
@ -34,6 +34,7 @@
|
|||||||
#include "../render/IImage.h"
|
#include "../render/IImage.h"
|
||||||
#include "../render/IRenderHandler.h"
|
#include "../render/IRenderHandler.h"
|
||||||
#include "../render/IScreenHandler.h"
|
#include "../render/IScreenHandler.h"
|
||||||
|
#include "../render/AssetGenerator.h"
|
||||||
#include "../CMT.h"
|
#include "../CMT.h"
|
||||||
#include "../PlayerLocalState.h"
|
#include "../PlayerLocalState.h"
|
||||||
#include "../CPlayerInterface.h"
|
#include "../CPlayerInterface.h"
|
||||||
@ -64,6 +65,8 @@ AdventureMapInterface::AdventureMapInterface():
|
|||||||
pos.w = GH.screenDimensions().x;
|
pos.w = GH.screenDimensions().x;
|
||||||
pos.h = GH.screenDimensions().y;
|
pos.h = GH.screenDimensions().y;
|
||||||
|
|
||||||
|
AssetGenerator::createPaletteShiftedSprites();
|
||||||
|
|
||||||
shortcuts = std::make_shared<AdventureMapShortcuts>(*this);
|
shortcuts = std::make_shared<AdventureMapShortcuts>(*this);
|
||||||
|
|
||||||
widget = std::make_shared<AdventureMapWidget>(shortcuts);
|
widget = std::make_shared<AdventureMapWidget>(shortcuts);
|
||||||
|
@ -121,21 +121,31 @@ void MapTileStorage::load(size_t index, const AnimationPath & filename, EImageBl
|
|||||||
terrainAnimations[3]->horizontalFlip();
|
terrainAnimations[3]->horizontalFlip();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IImage> MapTileStorage::find(size_t fileIndex, size_t rotationIndex, size_t imageIndex)
|
std::shared_ptr<IImage> MapTileStorage::find(size_t fileIndex, size_t rotationIndex, size_t imageIndex, size_t groupIndex)
|
||||||
{
|
{
|
||||||
const auto & animation = animations[fileIndex][rotationIndex];
|
const auto & animation = animations[fileIndex][rotationIndex];
|
||||||
if (animation)
|
if (animation)
|
||||||
return animation->getImage(imageIndex);
|
return animation->getImage(imageIndex, groupIndex);
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MapTileStorage::groupCount(size_t fileIndex, size_t rotationIndex, size_t imageIndex)
|
||||||
|
{
|
||||||
|
const auto & animation = animations[fileIndex][rotationIndex];
|
||||||
|
if (animation)
|
||||||
|
for(int i = 0;; i++)
|
||||||
|
if(!animation->getImage(imageIndex, i, false))
|
||||||
|
return i;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
MapRendererTerrain::MapRendererTerrain()
|
MapRendererTerrain::MapRendererTerrain()
|
||||||
: storage(VLC->terrainTypeHandler->objects.size())
|
: storage(VLC->terrainTypeHandler->objects.size())
|
||||||
{
|
{
|
||||||
logGlobal->debug("Loading map terrains");
|
logGlobal->debug("Loading map terrains");
|
||||||
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
||||||
storage.load(terrain->getIndex(), terrain->tilesFilename, EImageBlitMode::OPAQUE);
|
storage.load(terrain->getIndex(), AnimationPath::builtin(terrain->tilesFilename.getName() + (terrain->paletteAnimation.size() ? "_Shifted": "")), EImageBlitMode::OPAQUE);
|
||||||
logGlobal->debug("Done loading map terrains");
|
logGlobal->debug("Done loading map terrains");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +157,8 @@ void MapRendererTerrain::renderTile(IMapRendererContext & context, Canvas & targ
|
|||||||
int32_t imageIndex = mapTile.terView;
|
int32_t imageIndex = mapTile.terView;
|
||||||
int32_t rotationIndex = mapTile.extTileFlags % 4;
|
int32_t rotationIndex = mapTile.extTileFlags % 4;
|
||||||
|
|
||||||
const auto & image = storage.find(terrainIndex, rotationIndex, imageIndex);
|
int groupCount = storage.groupCount(terrainIndex, rotationIndex, imageIndex);
|
||||||
|
const auto & image = storage.find(terrainIndex, rotationIndex, imageIndex, groupCount > 1 ? context.terrainImageIndex(groupCount) : 0);
|
||||||
|
|
||||||
assert(image);
|
assert(image);
|
||||||
if (!image)
|
if (!image)
|
||||||
@ -156,9 +167,6 @@ void MapRendererTerrain::renderTile(IMapRendererContext & context, Canvas & targ
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( auto const & element : mapTile.getTerrain()->paletteAnimation)
|
|
||||||
image->shiftPalette(element.start, element.length, context.terrainImageIndex(element.length));
|
|
||||||
|
|
||||||
target.draw(image, Point(0, 0));
|
target.draw(image, Point(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +184,7 @@ MapRendererRiver::MapRendererRiver()
|
|||||||
{
|
{
|
||||||
logGlobal->debug("Loading map rivers");
|
logGlobal->debug("Loading map rivers");
|
||||||
for(const auto & river : VLC->riverTypeHandler->objects)
|
for(const auto & river : VLC->riverTypeHandler->objects)
|
||||||
storage.load(river->getIndex(), river->tilesFilename, EImageBlitMode::COLORKEY);
|
storage.load(river->getIndex(), AnimationPath::builtin(river->tilesFilename.getName() + (river->paletteAnimation.size() ? "_Shifted": "")), EImageBlitMode::COLORKEY);
|
||||||
logGlobal->debug("Done loading map rivers");
|
logGlobal->debug("Done loading map rivers");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,10 +199,8 @@ void MapRendererRiver::renderTile(IMapRendererContext & context, Canvas & target
|
|||||||
int32_t imageIndex = mapTile.riverDir;
|
int32_t imageIndex = mapTile.riverDir;
|
||||||
int32_t rotationIndex = (mapTile.extTileFlags >> 2) % 4;
|
int32_t rotationIndex = (mapTile.extTileFlags >> 2) % 4;
|
||||||
|
|
||||||
const auto & image = storage.find(terrainIndex, rotationIndex, imageIndex);
|
int groupCount = storage.groupCount(terrainIndex, rotationIndex, imageIndex);
|
||||||
|
const auto & image = storage.find(terrainIndex, rotationIndex, imageIndex, groupCount > 1 ? context.terrainImageIndex(groupCount) : 0);
|
||||||
for( auto const & element : mapTile.getRiver()->paletteAnimation)
|
|
||||||
image->shiftPalette(element.start, element.length, context.terrainImageIndex(element.length));
|
|
||||||
|
|
||||||
target.draw(image, Point(0, 0));
|
target.draw(image, Point(0, 0));
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,8 @@ class MapTileStorage
|
|||||||
public:
|
public:
|
||||||
explicit MapTileStorage(size_t capacity);
|
explicit MapTileStorage(size_t capacity);
|
||||||
void load(size_t index, const AnimationPath & filename, EImageBlitMode blitMode);
|
void load(size_t index, const AnimationPath & filename, EImageBlitMode blitMode);
|
||||||
std::shared_ptr<IImage> find(size_t fileIndex, size_t rotationIndex, size_t imageIndex);
|
std::shared_ptr<IImage> find(size_t fileIndex, size_t rotationIndex, size_t imageIndex, size_t groupIndex = 0);
|
||||||
|
int groupCount(size_t fileIndex, size_t rotationIndex, size_t imageIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapRendererTerrain
|
class MapRendererTerrain
|
||||||
|
@ -16,12 +16,16 @@
|
|||||||
#include "../render/Canvas.h"
|
#include "../render/Canvas.h"
|
||||||
#include "../render/ColorFilter.h"
|
#include "../render/ColorFilter.h"
|
||||||
#include "../render/IRenderHandler.h"
|
#include "../render/IRenderHandler.h"
|
||||||
|
#include "../render/CAnimation.h"
|
||||||
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/GameSettings.h"
|
#include "../lib/GameSettings.h"
|
||||||
#include "../lib/IGameSettings.h"
|
#include "../lib/IGameSettings.h"
|
||||||
#include "../lib/json/JsonNode.h"
|
#include "../lib/json/JsonNode.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
|
#include "../lib/RiverHandler.h"
|
||||||
|
#include "../lib/RoadHandler.h"
|
||||||
|
#include "../lib/TerrainHandler.h"
|
||||||
|
|
||||||
void AssetGenerator::generateAll()
|
void AssetGenerator::generateAll()
|
||||||
{
|
{
|
||||||
@ -32,6 +36,7 @@ void AssetGenerator::generateAll()
|
|||||||
createCombatUnitNumberWindow();
|
createCombatUnitNumberWindow();
|
||||||
createCampaignBackground();
|
createCampaignBackground();
|
||||||
createChroniclesCampaignImages();
|
createChroniclesCampaignImages();
|
||||||
|
createPaletteShiftedSprites();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetGenerator::createAdventureOptionsCleanBackground()
|
void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||||
@ -326,3 +331,106 @@ void AssetGenerator::createChroniclesCampaignImages()
|
|||||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < tiles.size(); i++)
|
||||||
|
{
|
||||||
|
auto sprite = tiles[i];
|
||||||
|
|
||||||
|
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);
|
||||||
|
imgLoc.scalingFactor = 1;
|
||||||
|
auto img = GH.renderHandler().loadImage(imgLoc, EImageBlitMode::COLORKEY);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas canvas = Canvas(Point(32, 32), CanvasScalingPolicy::IGNORE);
|
||||||
|
canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
|
||||||
|
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,4 +23,5 @@ public:
|
|||||||
static void createCombatUnitNumberWindow();
|
static void createCombatUnitNumberWindow();
|
||||||
static void createCampaignBackground();
|
static void createCampaignBackground();
|
||||||
static void createChroniclesCampaignImages();
|
static void createChroniclesCampaignImages();
|
||||||
|
static void createPaletteShiftedSprites();
|
||||||
};
|
};
|
||||||
|
@ -18,10 +18,11 @@
|
|||||||
#include "../../lib/filesystem/Filesystem.h"
|
#include "../../lib/filesystem/Filesystem.h"
|
||||||
#include "../../lib/json/JsonUtils.h"
|
#include "../../lib/json/JsonUtils.h"
|
||||||
|
|
||||||
bool CAnimation::loadFrame(size_t frame, size_t group)
|
bool CAnimation::loadFrame(size_t frame, size_t group, bool verbose)
|
||||||
{
|
{
|
||||||
if(size(group) <= frame)
|
if(size(group) <= frame)
|
||||||
{
|
{
|
||||||
|
if(verbose)
|
||||||
printError(frame, group, "LoadFrame");
|
printError(frame, group, "LoadFrame");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -119,7 +120,7 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra
|
|||||||
|
|
||||||
std::shared_ptr<IImage> CAnimation::getImage(size_t frame, size_t group, bool verbose)
|
std::shared_ptr<IImage> CAnimation::getImage(size_t frame, size_t group, bool verbose)
|
||||||
{
|
{
|
||||||
if (!loadFrame(frame, group))
|
if (!loadFrame(frame, group, verbose))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return getImageImpl(frame, group, verbose);
|
return getImageImpl(frame, group, verbose);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ private:
|
|||||||
PlayerColor player = PlayerColor::CANNOT_DETERMINE;
|
PlayerColor player = PlayerColor::CANNOT_DETERMINE;
|
||||||
|
|
||||||
//loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded
|
//loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded
|
||||||
bool loadFrame(size_t frame, size_t group);
|
bool loadFrame(size_t frame, size_t group, bool verbose = true);
|
||||||
|
|
||||||
//unloadFrame, returns true if image has been unloaded ( either deleted or decreased refCount)
|
//unloadFrame, returns true if image has been unloaded ( either deleted or decreased refCount)
|
||||||
bool unloadFrame(size_t frame, size_t group);
|
bool unloadFrame(size_t frame, size_t group);
|
||||||
@ -50,8 +50,6 @@ private:
|
|||||||
void printError(size_t frame, size_t group, std::string type) const;
|
void printError(size_t frame, size_t group, std::string type) const;
|
||||||
|
|
||||||
std::shared_ptr<IImage> getImageImpl(size_t frame, size_t group=0, bool verbose=true);
|
std::shared_ptr<IImage> getImageImpl(size_t frame, size_t group=0, bool verbose=true);
|
||||||
|
|
||||||
ImageLocator getImageLocator(size_t frame, size_t group) const;
|
|
||||||
public:
|
public:
|
||||||
CAnimation(const AnimationPath & Name, std::map<size_t, std::vector <ImageLocator> > layout, EImageBlitMode mode);
|
CAnimation(const AnimationPath & Name, std::map<size_t, std::vector <ImageLocator> > layout, EImageBlitMode mode);
|
||||||
~CAnimation();
|
~CAnimation();
|
||||||
@ -74,5 +72,7 @@ public:
|
|||||||
void playerColored(PlayerColor player);
|
void playerColored(PlayerColor player);
|
||||||
|
|
||||||
void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup);
|
void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup);
|
||||||
|
|
||||||
|
ImageLocator getImageLocator(size_t frame, size_t group) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,6 +86,11 @@ JsonNode::JsonNode(const std::string & string)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonNode::JsonNode(const JsonMap & map)
|
||||||
|
: data(map)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
JsonNode::JsonNode(const std::byte * data, size_t datasize, const std::string & fileName)
|
JsonNode::JsonNode(const std::byte * data, size_t datasize, const std::string & fileName)
|
||||||
: JsonNode(data, datasize, JsonParsingSettings(), fileName)
|
: JsonNode(data, datasize, JsonParsingSettings(), fileName)
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,9 @@ public:
|
|||||||
explicit JsonNode(const char * string);
|
explicit JsonNode(const char * string);
|
||||||
explicit JsonNode(const std::string & string);
|
explicit JsonNode(const std::string & string);
|
||||||
|
|
||||||
|
/// Create tree from map
|
||||||
|
explicit JsonNode(const JsonMap & map);
|
||||||
|
|
||||||
/// Create tree from Json-formatted input
|
/// Create tree from Json-formatted input
|
||||||
explicit JsonNode(const std::byte * data, size_t datasize, const std::string & fileName);
|
explicit JsonNode(const std::byte * data, size_t datasize, const std::string & fileName);
|
||||||
explicit JsonNode(const std::byte * data, size_t datasize, const JsonParsingSettings & parserSettings, const std::string & fileName);
|
explicit JsonNode(const std::byte * data, size_t datasize, const JsonParsingSettings & parserSettings, const std::string & fileName);
|
||||||
|
Loading…
Reference in New Issue
Block a user