1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Flipped images are now tracked by RenderHandler

This commit is contained in:
Ivan Savenko 2024-06-05 20:16:12 +00:00
parent 230add02e4
commit b850b6339f
10 changed files with 208 additions and 114 deletions

View File

@ -552,25 +552,21 @@ void BattleFieldController::calculateRangeLimitAndHighlightImages(uint8_t distan
void BattleFieldController::flipRangeLimitImagesIntoPositions(std::shared_ptr<CAnimation> images)
{
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::topRight])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::right])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRight])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRight])->horizontalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeft])->horizontalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottom])->horizontalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::topRightHalfCorner])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner])->horizontalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftHalfCorner])->horizontalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::rightHalf])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::topRightCorner])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner])->verticalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner])->horizontalFlip();
images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftCorner])->horizontalFlip();
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::topRight]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::right]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRight]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRight]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomLeft]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottom]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::topRightHalfCorner]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftHalfCorner]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::rightHalf]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::topRightCorner]);
images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner]);
images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftCorner]);
}
void BattleFieldController::showHighlightedHexes(Canvas & canvas)

View File

@ -323,8 +323,7 @@ MapRendererFow::MapRendererFow()
for(const int rotation : rotations)
{
fogOfWarPartialHide->duplicateImage(0, rotation, 0);
auto image = fogOfWarPartialHide->getImage(size, 0);
image->verticalFlip();
fogOfWarPartialHide->verticalFlip(size, 0);
size++;
}
}

View File

@ -30,42 +30,26 @@ bool CAnimation::loadFrame(size_t frame, size_t group)
return true;
}
std::shared_ptr<IImage> image;
//try to get image from def
if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL)
if(source[group][frame].isNull())
image = GH.renderHandler().loadImage(name, frame, group);
else
image = GH.renderHandler().loadImage(source[group][frame]);
if(image)
{
auto image = GH.renderHandler().loadImage(name, frame, group);
if(image)
{
images[group][frame] = image;
return true;
}
// still here? image is missing
images[group][frame] = image;
return true;
}
else
{
// image is missing
printError(frame, group, "LoadFrame");
images[group][frame] = GH.renderHandler().loadImage(ImagePath::builtin("DEFAULT"), EImageBlitMode::OPAQUE);
return false;
}
if (!source[group][frame]["file"].isNull())
{
auto img = GH.renderHandler().loadImage(ImagePath::fromJson(source[group][frame]["file"]), EImageBlitMode::ALPHA);
images[group][frame] = img;
return true;
}
if (!source[group][frame]["animation"].isNull())
{
AnimationPath animationFile = AnimationPath::fromJson(source[group][frame]["animation"]);
int32_t animationGroup = source[group][frame]["sourceGroup"].Integer();
int32_t animationFrame = source[group][frame]["sourceFrame"].Integer();
auto img = GH.renderHandler().loadImage(animationFile, animationFrame, animationGroup);
images[group][frame] = img;
return true;
}
return false;
}
bool CAnimation::unloadFrame(size_t frame, size_t group)
@ -145,14 +129,13 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra
return;
}
//todo: clone actual loaded Image object
JsonNode clone(source[sourceGroup][sourceFrame]);
if(clone.getType() == JsonNode::JsonType::DATA_NULL)
{
clone["animation"].String() = name.getName();
clone["sourceGroup"].Integer() = sourceGroup;
clone["sourceFrame"].Integer() = sourceFrame;
clone["group"].Integer() = sourceGroup;
clone["frame"].Integer() = sourceFrame;
}
source[targetGroup].push_back(clone);
@ -197,16 +180,60 @@ size_t CAnimation::size(size_t group) const
void CAnimation::horizontalFlip()
{
for(auto & group : images)
for(auto & image : group.second)
image.second->horizontalFlip();
for(auto & group : source)
for(size_t i = 0; i < group.second.size(); ++i)
horizontalFlip(i, group.first);
}
void CAnimation::verticalFlip()
{
for(auto & group : images)
for(auto & image : group.second)
image.second->verticalFlip();
for(auto & group : source)
for(size_t i = 0; i < group.second.size(); ++i)
verticalFlip(i, group.first);
}
void CAnimation::horizontalFlip(size_t frame, size_t group)
{
try
{
images.at(group).at(frame) = nullptr;
}
catch (const std::out_of_range &)
{
// ignore - image not loaded
}
JsonNode & config = source.at(group).at(frame);
if (config.isNull())
{
config["animation"].String() = name.getName();
config["frame"].Integer() = frame;
config["group"].Integer() = group;
}
config["horizontalFlip"].Bool() = !config["horizontalFlip"].Bool();
}
void CAnimation::verticalFlip(size_t frame, size_t group)
{
try
{
images.at(group).at(frame) = nullptr;
}
catch (const std::out_of_range &)
{
// ignore - image not loaded
}
JsonNode & config = source.at(group).at(frame);
if (config.isNull())
{
config["animation"].String() = name.getName();
config["frame"].Integer() = frame;
config["group"].Integer() = group;
}
config["verticalFlip"].Bool() = !config["verticalFlip"].Bool();
}
void CAnimation::playerColored(PlayerColor player)
@ -221,8 +248,6 @@ void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targe
for(size_t frame = 0; frame < size(sourceGroup); ++frame)
{
duplicateImage(sourceGroup, frame, targetGroup);
auto image = getImage(frame, targetGroup);
image->verticalFlip();
verticalFlip(frame, targetGroup);
}
}

View File

@ -62,6 +62,8 @@ public:
//total count of frames in group (including not loaded)
size_t size(size_t group=0) const;
void horizontalFlip(size_t frame, size_t group=0);
void verticalFlip(size_t frame, size_t group=0);
void horizontalFlip();
void verticalFlip();
void playerColored(PlayerColor player);

View File

@ -75,9 +75,6 @@ public:
//only indexed bitmaps with 7 special colors
virtual void setSpecialPalette(const SpecialPalette & SpecialPalette, uint32_t colorsToSkipMask) = 0;
virtual void horizontalFlip() = 0;
virtual void verticalFlip() = 0;
virtual ~IImage() = default;
};
@ -90,5 +87,9 @@ public:
virtual std::shared_ptr<IImage> createImageReference() = 0;
virtual std::shared_ptr<IConstImage> horizontalFlip() const = 0;
virtual std::shared_ptr<IConstImage> verticalFlip() const = 0;
virtual ~IConstImage() = default;
};

View File

@ -30,6 +30,7 @@ public:
virtual void onLibraryLoadingFinished(const Services * services) = 0;
/// Loads image using given path
virtual std::shared_ptr<IImage> loadImage(const JsonNode & config) = 0;
virtual std::shared_ptr<IImage> loadImage(const ImagePath & path) = 0;
virtual std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) = 0;
virtual std::shared_ptr<IImage> loadImage(const AnimationPath & path, int frame, int group) = 0;

View File

@ -27,6 +27,43 @@
#include <vcmi/SkillService.h>
#include <vcmi/spells/Service.h>
RenderHandler::ImageLocator::ImageLocator(const JsonNode & config)
: image(ImagePath::fromJson(config["file"]))
, animation(AnimationPath::fromJson(config["animation"]))
, frame(config["frame"].Integer())
, group(config["group"].Integer())
, verticalFlip(config["verticalFlip"].Bool())
, horizontalFlip(config["horizontalFlip"].Bool())
{
}
RenderHandler::ImageLocator::ImageLocator(const ImagePath & path)
: image(path)
{
}
RenderHandler::ImageLocator::ImageLocator(const AnimationPath & path, int frame, int group)
: animation(path)
, frame(frame)
, group(group)
{
}
bool RenderHandler::ImageLocator::operator<(const ImageLocator & other) const
{
if(image != other.image)
return image < other.image;
if(animation != other.animation)
return animation < other.animation;
if(group != other.group)
return group < other.group;
if(frame != other.frame)
return frame < other.frame;
if(verticalFlip != other.verticalFlip)
return verticalFlip < other.verticalFlip;
return horizontalFlip < other.horizontalFlip;
}
std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath & path)
{
AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/");
@ -103,7 +140,7 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
{
const std::map<size_t, size_t> defEntries = defFile->getEntries();
for (auto & defEntry : defEntries)
for (const auto & defEntry : defEntries)
result[defEntry.first].resize(defEntry.second);
}
@ -125,32 +162,78 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
return animationLayouts[actualPath];
}
std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group)
std::shared_ptr<IConstImage> RenderHandler::loadImageFromSingleFile(const ImagePath & path)
{
AnimationLocator locator{path, frame, group};
auto it = animationFrames.find(locator);
if (it != animationFrames.end())
return it->second->createImageReference();
auto result = std::make_shared<SDLImageConst>(path, EImageBlitMode::COLORKEY);
imageFiles[ImageLocator(path)] = result;
return result;
}
std::shared_ptr<IConstImage> RenderHandler::loadImageFromAnimationFileUncached(const AnimationPath & path, int frame, int group)
{
const auto & layout = getAnimationLayout(path);
if (!layout.count(group))
return loadImage(ImagePath::builtin("DEFAULT"));
return loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
if (frame >= layout.at(group).size())
return loadImage(ImagePath::builtin("DEFAULT"));
return loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
const auto & config = layout.at(group).at(frame);
if (config.isNull())
{
auto defFile = getAnimationFile(path);
auto result = std::make_shared<SDLImageConst>(defFile.get(), frame, group);
animationFrames[locator] = result;
return result->createImageReference();
return std::make_shared<SDLImageConst>(defFile.get(), frame, group);
}
else
{
return loadImageImpl(ImageLocator(config));
}
}
return loadImage(ImagePath::builtin("DEFAULT"));
std::shared_ptr<IConstImage> RenderHandler::loadImageFromAnimationFile(const AnimationPath & path, int frame, int group)
{
auto result = loadImageFromAnimationFileUncached(path, frame, group);
imageFiles[ImageLocator(path, frame, group)] = result;
return result;
}
std::shared_ptr<IConstImage> RenderHandler::loadImageImpl(const ImageLocator & locator)
{
auto it = imageFiles.find(locator);
if (it != imageFiles.end())
return it->second;
std::shared_ptr<IConstImage> result;
if (!locator.image.empty())
result = loadImageFromSingleFile(locator.image);
else if (!locator.animation.empty())
result = loadImageFromAnimationFile(locator.animation, locator.frame, locator.group);
if (!result)
result = loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
if (locator.verticalFlip)
result = result->verticalFlip();
if (locator.horizontalFlip)
result = result->horizontalFlip();
imageFiles[locator] = result;
return result;
}
std::shared_ptr<IImage> RenderHandler::loadImage(const JsonNode & config)
{
if (config.isString())
return loadImageImpl(ImageLocator(ImagePath::fromJson(config)))->createImageReference();
else
return loadImageImpl(ImageLocator(config))->createImageReference();
}
std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group)
{
return loadImageImpl(ImageLocator(path, frame, group))->createImageReference();
}
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path)
@ -160,13 +243,7 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path)
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
{
auto it = imageFiles.find(path);
if (it != imageFiles.end())
return it->second->createImageReference();
auto result = std::make_shared<SDLImageConst>(path, mode);
imageFiles[path] = result;
return result->createImageReference();
return loadImageImpl(ImageLocator(path))->createImageReference();
}
std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)

View File

@ -22,26 +22,25 @@ class RenderHandler : public IRenderHandler
{
using AnimationLayoutMap = std::map<size_t, std::vector<JsonNode>>;
struct AnimationLocator
struct ImageLocator
{
ImagePath image;
AnimationPath animation;
int frame = -1;
int group = -1;
bool operator < (const AnimationLocator & other) const
{
if (animation != other.animation)
return animation < other.animation;
if (group != other.group)
return group < other.group;
return frame < other.frame;
}
bool verticalFlip = false;
bool horizontalFlip = false;
ImageLocator(const JsonNode & config);
ImageLocator(const ImagePath & path);
ImageLocator(const AnimationPath & path, int frame, int group);
bool operator < (const ImageLocator & other) const;
};
std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
std::map<ImagePath, std::shared_ptr<IConstImage>> imageFiles;
std::map<AnimationLocator, std::shared_ptr<IConstImage>> animationFrames;
std::map<ImageLocator, std::shared_ptr<IConstImage>> imageFiles;
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
@ -49,11 +48,17 @@ class RenderHandler : public IRenderHandler
void addImageListEntry(size_t index, size_t group, const std::string & listName, const std::string & imageName);
void addImageListEntries(const EntityService * service);
std::shared_ptr<IConstImage> loadImageFromSingleFile(const ImagePath & path);
std::shared_ptr<IConstImage> loadImageFromAnimationFileUncached(const AnimationPath & path, int frame, int group);
std::shared_ptr<IConstImage> loadImageFromAnimationFile(const AnimationPath & path, int frame, int group);
std::shared_ptr<IConstImage> loadImageImpl(const ImageLocator & config);
public:
// IRenderHandler implementation
void onLibraryLoadingFinished(const Services * services) override;
std::shared_ptr<IImage> loadImage(const JsonNode & config) override;
std::shared_ptr<IImage> loadImage(const ImagePath & path) override;
std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) override;
std::shared_ptr<IImage> loadImage(const AnimationPath & path, int frame, int group) override;

View File

@ -202,7 +202,7 @@ std::shared_ptr<IImage> SDLImageConst::createImageReference()
return std::make_shared<SDLImageRGB>(shared_from_this());
}
std::shared_ptr<SDLImageConst> SDLImageConst::horizontalFlip() const
std::shared_ptr<IConstImage> SDLImageConst::horizontalFlip() const
{
SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf);
auto ret = std::make_shared<SDLImageConst>(flipped, EImageBlitMode::ALPHA);
@ -214,7 +214,7 @@ std::shared_ptr<SDLImageConst> SDLImageConst::horizontalFlip() const
return ret;
}
std::shared_ptr<SDLImageConst> SDLImageConst::verticalFlip() const
std::shared_ptr<IConstImage> SDLImageConst::verticalFlip() const
{
SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf);
auto ret = std::make_shared<SDLImageConst>(flipped, EImageBlitMode::ALPHA);
@ -342,16 +342,6 @@ void SDLImageBase::setBlitMode(EImageBlitMode mode)
blitMode = mode;
}
void SDLImageBase::horizontalFlip()
{
image = image->horizontalFlip();
}
void SDLImageBase::verticalFlip()
{
image = image->verticalFlip();
}
void SDLImageRGB::setSpecialPallete(const SpecialPalette & SpecialPalette, uint32_t colorsToSkipMask)
{}

View File

@ -53,8 +53,8 @@ public:
Point dimensions() const override;
bool isTransparent(const Point & coords) const override;
std::shared_ptr<IImage> createImageReference() override;
std::shared_ptr<SDLImageConst> horizontalFlip() const;
std::shared_ptr<SDLImageConst> verticalFlip() const;
std::shared_ptr<IConstImage> horizontalFlip() const override;
std::shared_ptr<IConstImage> verticalFlip() const override;
std::shared_ptr<SDLImageConst> scaleFast(const Point & size) const;
const SDL_Palette * getPalette() const;
@ -79,8 +79,6 @@ public:
Point dimensions() const override;
void setAlpha(uint8_t value) override;
void setBlitMode(EImageBlitMode mode) override;
void horizontalFlip() override;
void verticalFlip() override;
};
class SDLImageIndexed final : public SDLImageBase