1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-10-31 00:07:39 +02:00

prescaled image support

This commit is contained in:
Laserlicht
2024-11-03 13:38:15 +01:00
parent e45be3c5e6
commit 11b437db62
6 changed files with 96 additions and 17 deletions

View File

@@ -55,6 +55,58 @@ std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath &
return result;
}
std::optional<ResourcePath> RenderHandler::getPath(ResourcePath path)
{
if(CResourceHandler::get()->existsResource(path))
return path;
if(path.getType() == EResType::IMAGE)
{
auto p = ImagePath::builtin(path.getName());
if(CResourceHandler::get()->existsResource(p.addPrefix("DATA/")))
return std::optional<ResourcePath>(p.addPrefix("DATA/"));
if(CResourceHandler::get()->existsResource(p.addPrefix("SPRITES/")))
return std::optional<ResourcePath>(p.addPrefix("SPRITES/"));
}
else
{
auto p = AnimationPath::builtin(path.getName());
auto pJson = p.toType<EResType::JSON>();
if(CResourceHandler::get()->existsResource(p.addPrefix("SPRITES/")))
return std::optional<ResourcePath>(p.addPrefix("SPRITES/"));
if(CResourceHandler::get()->existsResource(pJson))
return std::optional<ResourcePath>(p);
if(CResourceHandler::get()->existsResource(pJson.addPrefix("SPRITES/")))
return std::optional<ResourcePath>(p.addPrefix("SPRITES/"));
}
return std::nullopt;
}
std::pair<ResourcePath, int> RenderHandler::getScalePath(ResourcePath p)
{
auto path = p;
auto name = p.getName();
int scaleFactor = 1;
if(getScalingFactor() > 1)
{
std::vector<int> factorsToCheck = {getScalingFactor(), 4, 3, 2};
for(auto factorToCheck : factorsToCheck)
{
ResourcePath scaledPath = ImagePath::builtin(name + "$" + std::to_string(factorToCheck));
if(p.getType() != EResType::IMAGE)
scaledPath = AnimationPath::builtin(name + "$" + std::to_string(factorToCheck));
if(getPath(scaledPath))
{
path = scaledPath;
scaleFactor = factorToCheck;
break;
}
}
}
return std::pair<ResourcePath, int>(path, scaleFactor);
};
void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config)
{
std::string basepath;
@@ -177,13 +229,13 @@ std::shared_ptr<ISharedImage> RenderHandler::loadImageFromFileUncached(const Ima
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);
return std::make_shared<SDLImageShared>(*locator.image, locator.preScaledFactor);
}
if (locator.defFile)
{
auto defFile = getAnimationFile(*locator.defFile);
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup);
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup, locator.preScaledFactor);
}
throw std::runtime_error("Invalid image locator received!");
@@ -247,7 +299,7 @@ std::shared_ptr<ISharedImage> RenderHandler::scaleImage(const ImageLocator & loc
if (locator.layer == EImageLayer::ALL && locator.playerColored != PlayerColor::CANNOT_DETERMINE)
handle->playerColored(locator.playerColored);
handle->scaleInteger(locator.scalingFactor);
handle->scaleInteger(locator.scalingFactor);
// TODO: try to optimize image size (possibly even before scaling?) - trim image borders if they are completely transparent
auto result = handle->getSharedImage();
@@ -284,13 +336,17 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator, E
std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
{
ImageLocator locator = getLocatorForAnimationFrame(path, frame, group);
auto tmp = getScalePath(path);
ImageLocator locator = getLocatorForAnimationFrame(AnimationPath::builtin(tmp.first.getName()), frame, group);
locator.preScaledFactor = tmp.second;
return loadImage(locator, mode);
}
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
{
ImageLocator locator(path);
auto tmp = getScalePath(path);
ImageLocator locator(ImagePath::builtin(tmp.first.getName()));
locator.preScaledFactor = tmp.second;
return loadImage(locator, mode);
}
@@ -301,7 +357,14 @@ std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)
{
return std::make_shared<CAnimation>(path, getAnimationLayout(path), mode);
auto tmp = getScalePath(path);
auto animPath = AnimationPath::builtin(tmp.first.getName());
auto layout = getAnimationLayout(animPath);
for(auto & g : layout)
for(auto & i : g.second)
i.preScaledFactor = tmp.second;
return std::make_shared<CAnimation>(animPath, layout, mode);
}
void RenderHandler::addImageListEntries(const EntityService * service)

View File

@@ -29,6 +29,8 @@ class RenderHandler : public IRenderHandler
std::map<EFonts, std::shared_ptr<const IFont>> fonts;
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
std::optional<ResourcePath> getPath(ResourcePath path);
std::pair<ResourcePath, int> getScalePath(ResourcePath p);
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
void initFromJson(AnimationLayoutMap & layout, const JsonNode & config);

View File

@@ -89,11 +89,12 @@ int IImage::height() const
return dimensions().y;
}
SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group)
SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group, int scaleFactor)
: surf(nullptr),
margins(0, 0),
fullSize(0, 0),
originalPalette(nullptr)
originalPalette(nullptr),
scaleFactor(scaleFactor)
{
SDLImageLoader loader(this);
data->loadFrame(frame, group, loader);
@@ -105,7 +106,8 @@ SDLImageShared::SDLImageShared(SDL_Surface * from)
: surf(nullptr),
margins(0, 0),
fullSize(0, 0),
originalPalette(nullptr)
originalPalette(nullptr),
scaleFactor(1)
{
surf = from;
if (surf == nullptr)
@@ -118,11 +120,12 @@ SDLImageShared::SDLImageShared(SDL_Surface * from)
fullSize.y = surf->h;
}
SDLImageShared::SDLImageShared(const ImagePath & filename)
SDLImageShared::SDLImageShared(const ImagePath & filename, int scaleFactor)
: surf(nullptr),
margins(0, 0),
fullSize(0, 0),
originalPalette(nullptr)
originalPalette(nullptr),
scaleFactor(scaleFactor)
{
surf = BitmapHandler::loadBitmap(filename);
@@ -274,7 +277,13 @@ std::shared_ptr<ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palet
if (palette && surf && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
SDL_Surface * scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ);
SDL_Surface * scaled = nullptr;
if(scaleFactor == factor)
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, 1, EScalingAlgorithm::NEAREST); // keep size
else if(scaleFactor == 1)
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ);
else
scaled = CSDL_Ext::scaleSurface(surf, (surf->w / scaleFactor) * factor, (surf->h / scaleFactor) * factor);
auto ret = std::make_shared<SDLImageShared>(scaled);
@@ -296,8 +305,8 @@ std::shared_ptr<ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palet
std::shared_ptr<ISharedImage> SDLImageShared::scaleTo(const Point & size, SDL_Palette * palette) const
{
float scaleX = float(size.x) / dimensions().x;
float scaleY = float(size.y) / dimensions().y;
float scaleX = float(size.x) / fullSize.x;
float scaleY = float(size.y) / fullSize.y;
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
@@ -355,7 +364,7 @@ bool SDLImageShared::isTransparent(const Point & coords) const
Point SDLImageShared::dimensions() const
{
return fullSize;
return fullSize / scaleFactor;
}
std::shared_ptr<IImage> SDLImageShared::createImageReference(EImageBlitMode mode)

View File

@@ -35,6 +35,9 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
//total size including borders
Point fullSize;
//pre scaled image
int scaleFactor;
// Keep the original palette, in order to do color switching operation
void savePalette();
@@ -42,9 +45,9 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
public:
//Load image from def file
SDLImageShared(const CDefFile *data, size_t frame, size_t group=0);
SDLImageShared(const CDefFile *data, size_t frame, size_t group=0, int scaleFactor=1);
//Load from bitmap file
SDLImageShared(const ImagePath & filename);
SDLImageShared(const ImagePath & filename, int scaleFactor=1);
//Create using existing surface, extraRef will increase refcount on SDL_Surface
SDLImageShared(SDL_Surface * from);
~SDLImageShared();