mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-31 22:05:10 +02:00
Reworked image container classes for easier support of new features
This commit is contained in:
parent
2ee5f2df02
commit
4a600a9d4c
@ -99,7 +99,7 @@ set(vcmiclientcommon_SRCS
|
|||||||
renderSDL/CursorHardware.cpp
|
renderSDL/CursorHardware.cpp
|
||||||
renderSDL/CursorSoftware.cpp
|
renderSDL/CursorSoftware.cpp
|
||||||
renderSDL/FontChain.cpp
|
renderSDL/FontChain.cpp
|
||||||
renderSDL/ImageScaled.cpp
|
renderSDL/ScalableImage.cpp
|
||||||
renderSDL/RenderHandler.cpp
|
renderSDL/RenderHandler.cpp
|
||||||
renderSDL/SDLImage.cpp
|
renderSDL/SDLImage.cpp
|
||||||
renderSDL/SDLImageLoader.cpp
|
renderSDL/SDLImageLoader.cpp
|
||||||
@ -307,7 +307,7 @@ set(vcmiclientcommon_HEADERS
|
|||||||
renderSDL/CursorHardware.h
|
renderSDL/CursorHardware.h
|
||||||
renderSDL/CursorSoftware.h
|
renderSDL/CursorSoftware.h
|
||||||
renderSDL/FontChain.h
|
renderSDL/FontChain.h
|
||||||
renderSDL/ImageScaled.h
|
renderSDL/ScalableImage.h
|
||||||
renderSDL/RenderHandler.h
|
renderSDL/RenderHandler.h
|
||||||
renderSDL/SDLImage.h
|
renderSDL/SDLImage.h
|
||||||
renderSDL/SDLImageLoader.h
|
renderSDL/SDLImageLoader.h
|
||||||
|
@ -58,10 +58,9 @@ void AssetGenerator::createAdventureOptionsCleanBackground()
|
|||||||
return;
|
return;
|
||||||
ResourcePath savePath(filename, EResType::IMAGE);
|
ResourcePath savePath(filename, EResType::IMAGE);
|
||||||
|
|
||||||
auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"));
|
auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"), EImageBlitMode::OPAQUE);
|
||||||
locator.scalingFactor = 1;
|
|
||||||
|
|
||||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
|
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||||
|
|
||||||
Canvas canvas = Canvas(Point(575, 585), CanvasScalingPolicy::IGNORE);
|
Canvas canvas = Canvas(Point(575, 585), CanvasScalingPolicy::IGNORE);
|
||||||
canvas.draw(img, Point(0, 0), Rect(0, 0, 575, 585));
|
canvas.draw(img, Point(0, 0), Rect(0, 0, 575, 585));
|
||||||
@ -88,10 +87,9 @@ void AssetGenerator::createBigSpellBook()
|
|||||||
return;
|
return;
|
||||||
ResourcePath savePath(filename, EResType::IMAGE);
|
ResourcePath savePath(filename, EResType::IMAGE);
|
||||||
|
|
||||||
auto locator = ImageLocator(ImagePath::builtin("SpelBack"));
|
auto locator = ImageLocator(ImagePath::builtin("SpelBack"), EImageBlitMode::OPAQUE);
|
||||||
locator.scalingFactor = 1;
|
|
||||||
|
|
||||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
|
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||||
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||||
// edges
|
// edges
|
||||||
canvas.draw(img, Point(0, 0), Rect(15, 38, 90, 45));
|
canvas.draw(img, Point(0, 0), Rect(15, 38, 90, 45));
|
||||||
@ -152,10 +150,9 @@ void AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
|||||||
|
|
||||||
ResourcePath savePath(filename, EResType::IMAGE);
|
ResourcePath savePath(filename, EResType::IMAGE);
|
||||||
|
|
||||||
auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"));
|
auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"), EImageBlitMode::OPAQUE);
|
||||||
locator.scalingFactor = 1;
|
|
||||||
|
|
||||||
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
|
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator);
|
||||||
|
|
||||||
// transform to make color of brown DIBOX.PCX texture match color of specified player
|
// transform to make color of brown DIBOX.PCX texture match color of specified player
|
||||||
auto filterSettings = VLC->settingsHandler->getFullConfig()["interface"]["playerColoredBackground"];
|
auto filterSettings = VLC->settingsHandler->getFullConfig()["interface"]["playerColoredBackground"];
|
||||||
@ -199,10 +196,10 @@ void AssetGenerator::createCombatUnitNumberWindow()
|
|||||||
!CResourceHandler::get("local")->createResource(savePathNegative.getOriginalName() + ".png"))
|
!CResourceHandler::get("local")->createResource(savePathNegative.getOriginalName() + ".png"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"));
|
auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"), EImageBlitMode::OPAQUE);
|
||||||
locator.scalingFactor = 1;
|
locator.layer = EImageBlitMode::OPAQUE;
|
||||||
|
|
||||||
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator, 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 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 shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );
|
||||||
@ -233,10 +230,9 @@ void AssetGenerator::createCampaignBackground()
|
|||||||
return;
|
return;
|
||||||
ResourcePath savePath(filename, EResType::IMAGE);
|
ResourcePath savePath(filename, EResType::IMAGE);
|
||||||
|
|
||||||
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"));
|
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
|
||||||
locator.scalingFactor = 1;
|
|
||||||
|
|
||||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
|
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||||
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||||
|
|
||||||
canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
|
canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
|
||||||
@ -263,9 +259,8 @@ void AssetGenerator::createCampaignBackground()
|
|||||||
canvas.draw(img, Point(404, 414), Rect(313, 74, 197, 114));
|
canvas.draw(img, Point(404, 414), Rect(313, 74, 197, 114));
|
||||||
|
|
||||||
// skull
|
// skull
|
||||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"));
|
auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"), EImageBlitMode::OPAQUE);
|
||||||
locatorSkull.scalingFactor = 1;
|
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull, EImageBlitMode::OPAQUE);
|
|
||||||
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
|
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
|
||||||
|
|
||||||
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
|
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
|
||||||
@ -290,10 +285,9 @@ void AssetGenerator::createChroniclesCampaignImages()
|
|||||||
continue;
|
continue;
|
||||||
ResourcePath savePath(filename, EResType::IMAGE);
|
ResourcePath savePath(filename, EResType::IMAGE);
|
||||||
|
|
||||||
auto locator = ImageLocator(imgPathBg);
|
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
|
||||||
locator.scalingFactor = 1;
|
|
||||||
|
|
||||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
|
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||||
Canvas canvas = Canvas(Point(200, 116), CanvasScalingPolicy::IGNORE);
|
Canvas canvas = Canvas(Point(200, 116), CanvasScalingPolicy::IGNORE);
|
||||||
|
|
||||||
switch (i)
|
switch (i)
|
||||||
@ -323,9 +317,8 @@ void AssetGenerator::createChroniclesCampaignImages()
|
|||||||
canvas.draw(img, Point(0, 0), Rect(268, 210, 200, 116));
|
canvas.draw(img, Point(0, 0), Rect(268, 210, 200, 116));
|
||||||
|
|
||||||
//skull
|
//skull
|
||||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"));
|
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"), EImageBlitMode::OPAQUE);
|
||||||
locatorSkull.scalingFactor = 1;
|
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull, EImageBlitMode::OPAQUE);
|
|
||||||
canvas.draw(imgSkull, Point(162, 94), Rect(162, 94, 41, 22));
|
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, 94), Rect(424, 304, 14, 4));
|
||||||
canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
|
canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
|
||||||
@ -403,8 +396,7 @@ void AssetGenerator::createPaletteShiftedSprites()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto imgLoc = anim->getImageLocator(j, 0);
|
auto imgLoc = anim->getImageLocator(j, 0);
|
||||||
imgLoc.scalingFactor = 1;
|
auto img = GH.renderHandler().loadImage(imgLoc);
|
||||||
auto img = GH.renderHandler().loadImage(imgLoc, EImageBlitMode::COLORKEY);
|
|
||||||
for(int k = 0; k < paletteAnimations[i].size(); k++)
|
for(int k = 0; k < paletteAnimations[i].size(); k++)
|
||||||
{
|
{
|
||||||
auto element = paletteAnimations[i][k];
|
auto element = paletteAnimations[i][k];
|
||||||
|
@ -30,7 +30,7 @@ bool CAnimation::loadFrame(size_t frame, size_t group, bool verbose)
|
|||||||
if(auto image = getImageImpl(frame, group, false))
|
if(auto image = getImageImpl(frame, group, false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::shared_ptr<IImage> image = GH.renderHandler().loadImage(getImageLocator(frame, group), mode);
|
std::shared_ptr<IImage> image = GH.renderHandler().loadImage(getImageLocator(frame, group));
|
||||||
|
|
||||||
if(image)
|
if(image)
|
||||||
{
|
{
|
||||||
@ -224,5 +224,5 @@ ImageLocator CAnimation::getImageLocator(size_t frame, size_t group) const
|
|||||||
throw std::runtime_error("Frame " + std::to_string(frame) + " of group " + std::to_string(group) + " is missing from animation " + name.getOriginalName() );
|
throw std::runtime_error("Frame " + std::to_string(frame) + " of group " + std::to_string(group) + " is missing from animation " + name.getOriginalName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImageLocator(name, frame, group);
|
return ImageLocator(name, frame, group, mode);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ void Canvas::draw(const std::shared_ptr<IImage>& image, const Point & pos)
|
|||||||
{
|
{
|
||||||
assert(image);
|
assert(image);
|
||||||
if (image)
|
if (image)
|
||||||
image->draw(surface, transformPos(pos));
|
image->draw(surface, transformPos(pos), nullptr, getScalingFactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::draw(const std::shared_ptr<IImage>& image, const Point & pos, const Rect & sourceRect)
|
void Canvas::draw(const std::shared_ptr<IImage>& image, const Point & pos, const Rect & sourceRect)
|
||||||
@ -114,7 +114,7 @@ void Canvas::draw(const std::shared_ptr<IImage>& image, const Point & pos, const
|
|||||||
Rect realSourceRect = sourceRect * getScalingFactor();
|
Rect realSourceRect = sourceRect * getScalingFactor();
|
||||||
assert(image);
|
assert(image);
|
||||||
if (image)
|
if (image)
|
||||||
image->draw(surface, transformPos(pos), &realSourceRect);
|
image->draw(surface, transformPos(pos), &realSourceRect, getScalingFactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::draw(const Canvas & image, const Point & pos)
|
void Canvas::draw(const Canvas & image, const Point & pos)
|
||||||
@ -218,11 +218,11 @@ void Canvas::fillTexture(const std::shared_ptr<IImage>& image)
|
|||||||
for (int y=0; y < surface->h; y+= imageArea.h)
|
for (int y=0; y < surface->h; y+= imageArea.h)
|
||||||
{
|
{
|
||||||
for (int x=0; x < surface->w; x+= imageArea.w)
|
for (int x=0; x < surface->w; x+= imageArea.w)
|
||||||
image->draw(surface, Point(renderArea.x + x * getScalingFactor(), renderArea.y + y * getScalingFactor()));
|
image->draw(surface, Point(renderArea.x + x * getScalingFactor(), renderArea.y + y * getScalingFactor()), nullptr, getScalingFactor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface * Canvas::getInternalSurface()
|
SDL_Surface * Canvas::getInternalSurface() const
|
||||||
{
|
{
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ public:
|
|||||||
int getScalingFactor() const;
|
int getScalingFactor() const;
|
||||||
|
|
||||||
/// Compatibility method. AVOID USAGE. To be removed once SDL abstraction layer is finished.
|
/// Compatibility method. AVOID USAGE. To be removed once SDL abstraction layer is finished.
|
||||||
SDL_Surface * getInternalSurface();
|
SDL_Surface * getInternalSurface() const;
|
||||||
|
|
||||||
/// get the render area
|
/// get the render area
|
||||||
Rect getRenderArea() const;
|
Rect getRenderArea() const;
|
||||||
|
@ -68,10 +68,9 @@ class IImage
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//draws image on surface "where" at position
|
//draws image on surface "where" at position
|
||||||
virtual void draw(SDL_Surface * where, const Point & pos, const Rect * src = nullptr) const = 0;
|
virtual void draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const = 0;
|
||||||
|
|
||||||
virtual void scaleTo(const Point & size) = 0;
|
virtual void scaleTo(const Point & size) = 0;
|
||||||
virtual void scaleInteger(int factor) = 0;
|
|
||||||
|
|
||||||
virtual void exportBitmap(const boost::filesystem::path & path) const = 0;
|
virtual void exportBitmap(const boost::filesystem::path & path) const = 0;
|
||||||
|
|
||||||
@ -92,13 +91,10 @@ public:
|
|||||||
virtual void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) = 0;
|
virtual void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) = 0;
|
||||||
|
|
||||||
virtual void setAlpha(uint8_t value) = 0;
|
virtual void setAlpha(uint8_t value) = 0;
|
||||||
virtual void setBlitMode(EImageBlitMode mode) = 0;
|
|
||||||
|
|
||||||
//only indexed bitmaps with 7 special colors
|
//only indexed bitmaps with 7 special colors
|
||||||
virtual void setOverlayColor(const ColorRGBA & color) = 0;
|
virtual void setOverlayColor(const ColorRGBA & color) = 0;
|
||||||
|
|
||||||
virtual std::shared_ptr<const ISharedImage> getSharedImage() const = 0;
|
|
||||||
|
|
||||||
virtual ~IImage() = default;
|
virtual ~IImage() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,13 +110,13 @@ public:
|
|||||||
virtual Rect contentRect() const = 0;
|
virtual Rect contentRect() const = 0;
|
||||||
virtual void draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const = 0;
|
virtual void draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const = 0;
|
virtual ~ISharedImage() = default;
|
||||||
|
|
||||||
|
virtual const SDL_Palette * getPalette() const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> horizontalFlip() const = 0;
|
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> horizontalFlip() const = 0;
|
||||||
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> verticalFlip() const = 0;
|
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> verticalFlip() const = 0;
|
||||||
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const = 0;
|
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const = 0;
|
||||||
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const = 0;
|
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual ~ISharedImage() = default;
|
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@ struct SDL_Surface;
|
|||||||
class IFont;
|
class IFont;
|
||||||
class IImage;
|
class IImage;
|
||||||
class CAnimation;
|
class CAnimation;
|
||||||
|
class SDLImageShared;
|
||||||
enum class EImageBlitMode : uint8_t;
|
enum class EImageBlitMode : uint8_t;
|
||||||
enum EFonts : int8_t;
|
enum EFonts : int8_t;
|
||||||
|
|
||||||
@ -32,10 +33,13 @@ public:
|
|||||||
virtual void onLibraryLoadingFinished(const Services * services) = 0;
|
virtual void onLibraryLoadingFinished(const Services * services) = 0;
|
||||||
|
|
||||||
/// Loads image using given path
|
/// Loads image using given path
|
||||||
virtual std::shared_ptr<IImage> loadImage(const ImageLocator & locator, EImageBlitMode mode) = 0;
|
virtual std::shared_ptr<IImage> loadImage(const ImageLocator & locator) = 0;
|
||||||
virtual std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) = 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, EImageBlitMode mode) = 0;
|
virtual std::shared_ptr<IImage> loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode) = 0;
|
||||||
|
|
||||||
|
/// Loads single image without scaling support
|
||||||
|
virtual std::shared_ptr<SDLImageShared> loadSingleImage(const ImageLocator & locator) = 0;
|
||||||
|
|
||||||
/// temporary compatibility method. Creates IImage from existing SDL_Surface
|
/// temporary compatibility method. Creates IImage from existing SDL_Surface
|
||||||
/// Surface will be shared, caller must still free it with SDL_FreeSurface
|
/// Surface will be shared, caller must still free it with SDL_FreeSurface
|
||||||
virtual std::shared_ptr<IImage> createImage(SDL_Surface * source) = 0;
|
virtual std::shared_ptr<IImage> createImage(SDL_Surface * source) = 0;
|
||||||
|
@ -15,11 +15,10 @@
|
|||||||
|
|
||||||
#include "../../lib/json/JsonNode.h"
|
#include "../../lib/json/JsonNode.h"
|
||||||
|
|
||||||
ImageLocator::ImageLocator(const JsonNode & config)
|
SharedImageLocator::SharedImageLocator(const JsonNode & config, EImageBlitMode mode)
|
||||||
: defFrame(config["defFrame"].Integer())
|
: defFrame(config["defFrame"].Integer())
|
||||||
, defGroup(config["defGroup"].Integer())
|
, defGroup(config["defGroup"].Integer())
|
||||||
, verticalFlip(config["verticalFlip"].Bool())
|
, layer(mode)
|
||||||
, horizontalFlip(config["horizontalFlip"].Bool())
|
|
||||||
{
|
{
|
||||||
if(!config["file"].isNull())
|
if(!config["file"].isNull())
|
||||||
image = ImagePath::fromJson(config["file"]);
|
image = ImagePath::fromJson(config["file"]);
|
||||||
@ -28,19 +27,28 @@ ImageLocator::ImageLocator(const JsonNode & config)
|
|||||||
defFile = AnimationPath::fromJson(config["defFile"]);
|
defFile = AnimationPath::fromJson(config["defFile"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageLocator::ImageLocator(const ImagePath & path)
|
SharedImageLocator::SharedImageLocator(const ImagePath & path, EImageBlitMode mode)
|
||||||
: image(path)
|
: image(path)
|
||||||
|
, layer(mode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageLocator::ImageLocator(const AnimationPath & path, int frame, int group)
|
SharedImageLocator::SharedImageLocator(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
|
||||||
: defFile(path)
|
: defFile(path)
|
||||||
, defFrame(frame)
|
, defFrame(frame)
|
||||||
, defGroup(group)
|
, defGroup(group)
|
||||||
|
, layer(mode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageLocator::operator<(const ImageLocator & other) const
|
ImageLocator::ImageLocator(const JsonNode & config, EImageBlitMode mode)
|
||||||
|
: SharedImageLocator(config, mode)
|
||||||
|
, verticalFlip(config["verticalFlip"].Bool())
|
||||||
|
, horizontalFlip(config["horizontalFlip"].Bool())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedImageLocator::operator < (const SharedImageLocator & other) const
|
||||||
{
|
{
|
||||||
if(image != other.image)
|
if(image != other.image)
|
||||||
return image < other.image;
|
return image < other.image;
|
||||||
@ -50,14 +58,6 @@ bool ImageLocator::operator<(const ImageLocator & other) const
|
|||||||
return defGroup < other.defGroup;
|
return defGroup < other.defGroup;
|
||||||
if(defFrame != other.defFrame)
|
if(defFrame != other.defFrame)
|
||||||
return defFrame < other.defFrame;
|
return defFrame < other.defFrame;
|
||||||
if(verticalFlip != other.verticalFlip)
|
|
||||||
return verticalFlip < other.verticalFlip;
|
|
||||||
if(horizontalFlip != other.horizontalFlip)
|
|
||||||
return horizontalFlip < other.horizontalFlip;
|
|
||||||
if(scalingFactor != other.scalingFactor)
|
|
||||||
return scalingFactor < other.scalingFactor;
|
|
||||||
if(playerColored != other.playerColored)
|
|
||||||
return playerColored < other.playerColored;
|
|
||||||
if(layer != other.layer)
|
if(layer != other.layer)
|
||||||
return layer < other.layer;
|
return layer < other.layer;
|
||||||
|
|
||||||
@ -68,70 +68,3 @@ bool ImageLocator::empty() const
|
|||||||
{
|
{
|
||||||
return !image.has_value() && !defFile.has_value();
|
return !image.has_value() && !defFile.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageLocator ImageLocator::copyFile() const
|
|
||||||
{
|
|
||||||
ImageLocator result;
|
|
||||||
result.scalingFactor = 1;
|
|
||||||
result.preScaledFactor = preScaledFactor;
|
|
||||||
result.image = image;
|
|
||||||
result.defFile = defFile;
|
|
||||||
result.defFrame = defFrame;
|
|
||||||
result.defGroup = defGroup;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageLocator ImageLocator::copyFileTransform() const
|
|
||||||
{
|
|
||||||
ImageLocator result = copyFile();
|
|
||||||
result.horizontalFlip = horizontalFlip;
|
|
||||||
result.verticalFlip = verticalFlip;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageLocator ImageLocator::copyFileTransformScale() const
|
|
||||||
{
|
|
||||||
return *this; // full copy
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ImageLocator::toString() const
|
|
||||||
{
|
|
||||||
std::string result;
|
|
||||||
if (empty())
|
|
||||||
return "invalid";
|
|
||||||
|
|
||||||
if (image)
|
|
||||||
{
|
|
||||||
result += image->getOriginalName();
|
|
||||||
assert(!result.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defFile)
|
|
||||||
{
|
|
||||||
result += defFile->getOriginalName();
|
|
||||||
assert(!result.empty());
|
|
||||||
result += "-" + std::to_string(defGroup);
|
|
||||||
result += "-" + std::to_string(defFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verticalFlip)
|
|
||||||
result += "-vflip";
|
|
||||||
|
|
||||||
if (horizontalFlip)
|
|
||||||
result += "-hflip";
|
|
||||||
|
|
||||||
if (scalingFactor > 1)
|
|
||||||
result += "-scale" + std::to_string(scalingFactor);
|
|
||||||
|
|
||||||
if (playerColored.isValidPlayer())
|
|
||||||
result += "-player" + playerColored.toString();
|
|
||||||
|
|
||||||
if (layer == EImageBlitMode::ONLY_OVERLAY)
|
|
||||||
result += "-overlay";
|
|
||||||
|
|
||||||
if (layer == EImageBlitMode::ONLY_SHADOW)
|
|
||||||
result += "-shadow";
|
|
||||||
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
@ -14,35 +14,32 @@
|
|||||||
#include "../../lib/filesystem/ResourcePath.h"
|
#include "../../lib/filesystem/ResourcePath.h"
|
||||||
#include "../../lib/constants/EntityIdentifiers.h"
|
#include "../../lib/constants/EntityIdentifiers.h"
|
||||||
|
|
||||||
struct ImageLocator
|
struct SharedImageLocator
|
||||||
{
|
{
|
||||||
std::optional<ImagePath> image;
|
std::optional<ImagePath> image;
|
||||||
std::optional<AnimationPath> defFile;
|
std::optional<AnimationPath> defFile;
|
||||||
int defFrame = -1;
|
int defFrame = -1;
|
||||||
int defGroup = -1;
|
int defGroup = -1;
|
||||||
|
EImageBlitMode layer = EImageBlitMode::OPAQUE;
|
||||||
|
|
||||||
PlayerColor playerColored = PlayerColor::CANNOT_DETERMINE; // FIXME: treat as identical to blue to avoid double-loading?
|
SharedImageLocator() = default;
|
||||||
|
SharedImageLocator(const AnimationPath & path, int frame, int group, EImageBlitMode layer);
|
||||||
|
SharedImageLocator(const JsonNode & config, EImageBlitMode layer);
|
||||||
|
SharedImageLocator(const ImagePath & path, EImageBlitMode layer);
|
||||||
|
|
||||||
|
bool operator < (const SharedImageLocator & other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImageLocator : SharedImageLocator
|
||||||
|
{
|
||||||
|
PlayerColor playerColored = PlayerColor::CANNOT_DETERMINE;
|
||||||
|
|
||||||
bool verticalFlip = false;
|
bool verticalFlip = false;
|
||||||
bool horizontalFlip = false;
|
bool horizontalFlip = false;
|
||||||
int8_t scalingFactor = 0; // 0 = auto / use default scaling
|
int8_t scalingFactor = 0; // 0 = auto / use default scaling
|
||||||
int8_t preScaledFactor = 1;
|
|
||||||
EImageBlitMode layer = EImageBlitMode::OPAQUE;
|
|
||||||
|
|
||||||
ImageLocator() = default;
|
using SharedImageLocator::SharedImageLocator;
|
||||||
ImageLocator(const AnimationPath & path, int frame, int group);
|
ImageLocator(const JsonNode & config, EImageBlitMode layer);
|
||||||
explicit ImageLocator(const JsonNode & config);
|
|
||||||
explicit ImageLocator(const ImagePath & path);
|
|
||||||
|
|
||||||
bool operator < (const ImageLocator & other) const;
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
ImageLocator copyFile() const;
|
|
||||||
ImageLocator copyFileTransform() const;
|
|
||||||
ImageLocator copyFileTransformScale() const;
|
|
||||||
|
|
||||||
// generates string representation of this image locator
|
|
||||||
// guaranteed to be a valid file path with no extension
|
|
||||||
// but may contain '/' if source file is in directory
|
|
||||||
std::string toString() const;
|
|
||||||
};
|
};
|
||||||
|
@ -59,7 +59,7 @@ void CursorHardware::setImage(std::shared_ptr<IImage> image, const Point & pivot
|
|||||||
|
|
||||||
CSDL_Ext::fillSurface(cursorSurface, CSDL_Ext::toSDL(Colors::TRANSPARENCY));
|
CSDL_Ext::fillSurface(cursorSurface, CSDL_Ext::toSDL(Colors::TRANSPARENCY));
|
||||||
|
|
||||||
image->draw(cursorSurface, Point(0,0));
|
image->draw(cursorSurface, Point(0,0), nullptr, GH.screenHandler().getScalingFactor());
|
||||||
auto cursorSurfaceScaled = CSDL_Ext::scaleSurface(cursorSurface, cursorDimensionsScaled.x, cursorDimensionsScaled.y );
|
auto cursorSurfaceScaled = CSDL_Ext::scaleSurface(cursorSurface, cursorDimensionsScaled.x, cursorDimensionsScaled.y );
|
||||||
|
|
||||||
auto oldCursor = cursor;
|
auto oldCursor = cursor;
|
||||||
|
@ -65,7 +65,7 @@ void CursorSoftware::updateTexture()
|
|||||||
|
|
||||||
CSDL_Ext::fillSurface(cursorSurface, CSDL_Ext::toSDL(Colors::TRANSPARENCY));
|
CSDL_Ext::fillSurface(cursorSurface, CSDL_Ext::toSDL(Colors::TRANSPARENCY));
|
||||||
|
|
||||||
cursorImage->draw(cursorSurface, Point(0,0));
|
cursorImage->draw(cursorSurface, Point(0,0), nullptr, GH.screenHandler().getScalingFactor());
|
||||||
SDL_UpdateTexture(cursorTexture, nullptr, cursorSurface->pixels, cursorSurface->pitch);
|
SDL_UpdateTexture(cursorTexture, nullptr, cursorSurface->pixels, cursorSurface->pitch);
|
||||||
needUpdate = false;
|
needUpdate = false;
|
||||||
}
|
}
|
||||||
|
@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* ImageScaled.cpp, part of VCMI engine
|
|
||||||
*
|
|
||||||
* Authors: listed in file AUTHORS in main folder
|
|
||||||
*
|
|
||||||
* License: GNU General Public License v2.0 or later
|
|
||||||
* Full text of license available in license.txt file, in main folder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include "StdInc.h"
|
|
||||||
#include "ImageScaled.h"
|
|
||||||
|
|
||||||
#include "SDLImage.h"
|
|
||||||
#include "SDL_Extensions.h"
|
|
||||||
|
|
||||||
#include "../gui/CGuiHandler.h"
|
|
||||||
#include "../render/IScreenHandler.h"
|
|
||||||
#include "../render/Colors.h"
|
|
||||||
|
|
||||||
#include "../../lib/constants/EntityIdentifiers.h"
|
|
||||||
|
|
||||||
#include <SDL_surface.h>
|
|
||||||
|
|
||||||
ImageScaled::ImageScaled(const ImageLocator & inputLocator, const std::shared_ptr<const ISharedImage> & source, EImageBlitMode mode)
|
|
||||||
: source(source)
|
|
||||||
, locator(inputLocator)
|
|
||||||
, colorMultiplier(Colors::WHITE_TRUE)
|
|
||||||
, alphaValue(SDL_ALPHA_OPAQUE)
|
|
||||||
, blitMode(mode)
|
|
||||||
{
|
|
||||||
prepareImages();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> ImageScaled::getSharedImage() const
|
|
||||||
{
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::scaleInteger(int factor)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::scaleTo(const Point & size)
|
|
||||||
{
|
|
||||||
if (source)
|
|
||||||
source = source->scaleTo(size, nullptr);
|
|
||||||
|
|
||||||
if (body)
|
|
||||||
body = body->scaleTo(size * GH.screenHandler().getScalingFactor(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::exportBitmap(const boost::filesystem::path &path) const
|
|
||||||
{
|
|
||||||
source->exportBitmap(path, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImageScaled::isTransparent(const Point &coords) const
|
|
||||||
{
|
|
||||||
return source->isTransparent(coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect ImageScaled::contentRect() const
|
|
||||||
{
|
|
||||||
return source->contentRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
Point ImageScaled::dimensions() const
|
|
||||||
{
|
|
||||||
return source->dimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::setAlpha(uint8_t value)
|
|
||||||
{
|
|
||||||
alphaValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::setBlitMode(EImageBlitMode mode)
|
|
||||||
{
|
|
||||||
blitMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::draw(SDL_Surface *where, const Point &pos, const Rect *src) const
|
|
||||||
{
|
|
||||||
if (shadow)
|
|
||||||
shadow->draw(where, nullptr, pos, src, Colors::WHITE_TRUE, alphaValue, blitMode);
|
|
||||||
if (body)
|
|
||||||
body->draw(where, nullptr, pos, src, Colors::WHITE_TRUE, alphaValue, blitMode);
|
|
||||||
if (overlay)
|
|
||||||
overlay->draw(where, nullptr, pos, src, colorMultiplier, colorMultiplier.a * alphaValue / 255, blitMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::setOverlayColor(const ColorRGBA & color)
|
|
||||||
{
|
|
||||||
colorMultiplier = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::playerColored(PlayerColor player)
|
|
||||||
{
|
|
||||||
playerColor = player;
|
|
||||||
prepareImages();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::adjustPalette(const ColorFilter &shifter, uint32_t colorsToSkipMask)
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageScaled::prepareImages()
|
|
||||||
{
|
|
||||||
switch(blitMode)
|
|
||||||
{
|
|
||||||
case EImageBlitMode::OPAQUE:
|
|
||||||
case EImageBlitMode::COLORKEY:
|
|
||||||
case EImageBlitMode::SIMPLE:
|
|
||||||
locator.layer = blitMode;
|
|
||||||
locator.playerColored = playerColor;
|
|
||||||
body = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
|
||||||
case EImageBlitMode::ONLY_BODY:
|
|
||||||
locator.layer = EImageBlitMode::ONLY_BODY;
|
|
||||||
locator.playerColored = playerColor;
|
|
||||||
body = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EImageBlitMode::WITH_SHADOW:
|
|
||||||
case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
|
|
||||||
locator.layer = EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY;
|
|
||||||
locator.playerColored = playerColor;
|
|
||||||
body = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EImageBlitMode::ONLY_SHADOW:
|
|
||||||
case EImageBlitMode::ONLY_OVERLAY:
|
|
||||||
body = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(blitMode)
|
|
||||||
{
|
|
||||||
case EImageBlitMode::WITH_SHADOW:
|
|
||||||
case EImageBlitMode::ONLY_SHADOW:
|
|
||||||
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
|
||||||
locator.layer = EImageBlitMode::ONLY_SHADOW;
|
|
||||||
locator.playerColored = PlayerColor::CANNOT_DETERMINE;
|
|
||||||
shadow = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
shadow = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(blitMode)
|
|
||||||
{
|
|
||||||
case EImageBlitMode::ONLY_OVERLAY:
|
|
||||||
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
|
||||||
locator.layer = EImageBlitMode::ONLY_OVERLAY;
|
|
||||||
locator.playerColored = PlayerColor::CANNOT_DETERMINE;
|
|
||||||
overlay = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
overlay = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* ImageScaled.h, part of VCMI engine
|
|
||||||
*
|
|
||||||
* Authors: listed in file AUTHORS in main folder
|
|
||||||
*
|
|
||||||
* License: GNU General Public License v2.0 or later
|
|
||||||
* Full text of license available in license.txt file, in main folder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../render/IImage.h"
|
|
||||||
#include "../render/IRenderHandler.h"
|
|
||||||
|
|
||||||
#include "../../lib/Color.h"
|
|
||||||
#include "../../lib/constants/EntityIdentifiers.h"
|
|
||||||
|
|
||||||
struct SDL_Palette;
|
|
||||||
|
|
||||||
class SDLImageShared;
|
|
||||||
|
|
||||||
// Upscaled image with several mechanisms to emulate H3 palette effects
|
|
||||||
class ImageScaled final : public IImage
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
/// Original unscaled image
|
|
||||||
std::shared_ptr<const ISharedImage> source;
|
|
||||||
|
|
||||||
/// Upscaled shadow of our image, may be null
|
|
||||||
std::shared_ptr<const ISharedImage> shadow;
|
|
||||||
|
|
||||||
/// Upscaled main part of our image, may be null
|
|
||||||
std::shared_ptr<const ISharedImage> body;
|
|
||||||
|
|
||||||
/// Upscaled overlay (player color, selection highlight) of our image, may be null
|
|
||||||
std::shared_ptr<const ISharedImage> overlay;
|
|
||||||
|
|
||||||
ImageLocator locator;
|
|
||||||
|
|
||||||
ColorRGBA colorMultiplier;
|
|
||||||
PlayerColor playerColor = PlayerColor::CANNOT_DETERMINE;
|
|
||||||
|
|
||||||
uint8_t alphaValue;
|
|
||||||
EImageBlitMode blitMode;
|
|
||||||
|
|
||||||
void prepareImages();
|
|
||||||
public:
|
|
||||||
ImageScaled(const ImageLocator & locator, const std::shared_ptr<const ISharedImage> & source, EImageBlitMode mode);
|
|
||||||
|
|
||||||
void scaleInteger(int factor) override;
|
|
||||||
void scaleTo(const Point & size) override;
|
|
||||||
void exportBitmap(const boost::filesystem::path & path) const override;
|
|
||||||
bool isTransparent(const Point & coords) const override;
|
|
||||||
Rect contentRect() const override;
|
|
||||||
Point dimensions() const override;
|
|
||||||
void setAlpha(uint8_t value) override;
|
|
||||||
void setBlitMode(EImageBlitMode mode) override;
|
|
||||||
void draw(SDL_Surface * where, const Point & pos, const Rect * src) const override;
|
|
||||||
void setOverlayColor(const ColorRGBA & color) override;
|
|
||||||
void playerColored(PlayerColor player) override;
|
|
||||||
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override;
|
|
||||||
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;
|
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> getSharedImage() const override;
|
|
||||||
};
|
|
@ -11,7 +11,7 @@
|
|||||||
#include "RenderHandler.h"
|
#include "RenderHandler.h"
|
||||||
|
|
||||||
#include "SDLImage.h"
|
#include "SDLImage.h"
|
||||||
#include "ImageScaled.h"
|
#include "ScalableImage.h"
|
||||||
#include "FontChain.h"
|
#include "FontChain.h"
|
||||||
|
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "../render/ColorFilter.h"
|
#include "../render/ColorFilter.h"
|
||||||
#include "../render/IScreenHandler.h"
|
#include "../render/IScreenHandler.h"
|
||||||
#include "../../lib/json/JsonUtils.h"
|
#include "../../lib/json/JsonUtils.h"
|
||||||
|
#include "../../lib/CThreadHelper.h"
|
||||||
#include "../../lib/filesystem/Filesystem.h"
|
#include "../../lib/filesystem/Filesystem.h"
|
||||||
#include "../../lib/VCMIDirs.h"
|
#include "../../lib/VCMIDirs.h"
|
||||||
|
|
||||||
@ -55,60 +56,7 @@ std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath &
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ResourcePath> RenderHandler::getPathForScaleFactor(const ResourcePath & path, const std::string & factor)
|
void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config, EImageBlitMode mode)
|
||||||
{
|
|
||||||
if(path.getType() == EResType::IMAGE)
|
|
||||||
{
|
|
||||||
auto p = ImagePath::builtin(path.getName());
|
|
||||||
if(CResourceHandler::get()->existsResource(p.addPrefix("SPRITES" + factor + "X/")))
|
|
||||||
return std::optional<ResourcePath>(p.addPrefix("SPRITES" + factor + "X/"));
|
|
||||||
if(CResourceHandler::get()->existsResource(p.addPrefix("DATA" + factor + "X/")))
|
|
||||||
return std::optional<ResourcePath>(p.addPrefix("DATA" + factor + "X/"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto p = AnimationPath::builtin(path.getName());
|
|
||||||
auto pJson = p.toType<EResType::JSON>();
|
|
||||||
if(CResourceHandler::get()->existsResource(p.addPrefix("SPRITES" + factor + "X/")))
|
|
||||||
return std::optional<ResourcePath>(p.addPrefix("SPRITES" + factor + "X/"));
|
|
||||||
if(CResourceHandler::get()->existsResource(pJson))
|
|
||||||
return std::optional<ResourcePath>(p);
|
|
||||||
if(CResourceHandler::get()->existsResource(pJson.addPrefix("SPRITES" + factor + "X/")))
|
|
||||||
return std::optional<ResourcePath>(p.addPrefix("SPRITES" + factor + "X/"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<ResourcePath, int> RenderHandler::getScalePath(const ResourcePath & p)
|
|
||||||
{
|
|
||||||
auto path = p;
|
|
||||||
int scaleFactor = 1;
|
|
||||||
if(getScalingFactor() > 1)
|
|
||||||
{
|
|
||||||
std::vector<int> factorsToCheck = {getScalingFactor(), 4, 3, 2};
|
|
||||||
for(auto factorToCheck : factorsToCheck)
|
|
||||||
{
|
|
||||||
std::string name = boost::algorithm::to_upper_copy(p.getName());
|
|
||||||
boost::replace_all(name, "SPRITES/", std::string("SPRITES") + std::to_string(factorToCheck) + std::string("X/"));
|
|
||||||
boost::replace_all(name, "DATA/", std::string("DATA") + std::to_string(factorToCheck) + std::string("X/"));
|
|
||||||
ResourcePath scaledPath = ImagePath::builtin(name);
|
|
||||||
if(p.getType() != EResType::IMAGE)
|
|
||||||
scaledPath = AnimationPath::builtin(name);
|
|
||||||
auto tmpPath = getPathForScaleFactor(scaledPath, std::to_string(factorToCheck));
|
|
||||||
if(tmpPath)
|
|
||||||
{
|
|
||||||
path = *tmpPath;
|
|
||||||
scaleFactor = factorToCheck;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::pair<ResourcePath, int>(path, scaleFactor);
|
|
||||||
};
|
|
||||||
|
|
||||||
void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config)
|
|
||||||
{
|
{
|
||||||
std::string basepath;
|
std::string basepath;
|
||||||
basepath = config["basepath"].String();
|
basepath = config["basepath"].String();
|
||||||
@ -128,7 +76,7 @@ void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & c
|
|||||||
JsonNode toAdd = frame;
|
JsonNode toAdd = frame;
|
||||||
JsonUtils::inherit(toAdd, base);
|
JsonUtils::inherit(toAdd, base);
|
||||||
toAdd["file"].String() = basepath + frame.String();
|
toAdd["file"].String() = basepath + frame.String();
|
||||||
source[groupID].emplace_back(toAdd);
|
source[groupID].emplace_back(toAdd, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,15 +97,26 @@ void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & c
|
|||||||
if (toAdd.Struct().count("defFile"))
|
if (toAdd.Struct().count("defFile"))
|
||||||
toAdd["defFile"].String() = basepath + node["defFile"].String();
|
toAdd["defFile"].String() = basepath + node["defFile"].String();
|
||||||
|
|
||||||
source[group][frame] = ImageLocator(toAdd);
|
source[group][frame] = ImageLocator(toAdd, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const AnimationPath & path)
|
RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const AnimationPath & path, int scalingFactor, EImageBlitMode mode)
|
||||||
{
|
{
|
||||||
auto tmp = getScalePath(path);
|
static constexpr std::array scaledSpritesPath = {
|
||||||
auto animPath = AnimationPath::builtin(tmp.first.getName());
|
"", // 0x
|
||||||
AnimationPath actualPath = boost::starts_with(animPath.getName(), "SPRITES") ? animPath : animPath.addPrefix("SPRITES/");
|
"SPRITES/",
|
||||||
|
"SPRITES2X/",
|
||||||
|
"SPRITES3X/",
|
||||||
|
"SPRITES4X/",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string pathString = path.getName();
|
||||||
|
|
||||||
|
if (boost::starts_with(pathString, "SPRITES/"))
|
||||||
|
pathString = pathString.substr(std::string("SPRITES/").length());
|
||||||
|
|
||||||
|
AnimationPath actualPath = AnimationPath::builtin(scaledSpritesPath.at(scalingFactor) + pathString);
|
||||||
|
|
||||||
auto it = animationLayouts.find(actualPath);
|
auto it = animationLayouts.find(actualPath);
|
||||||
|
|
||||||
@ -184,15 +143,11 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
|
|||||||
std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
|
std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
|
||||||
stream->read(textData.get(), stream->getSize());
|
stream->read(textData.get(), stream->getSize());
|
||||||
|
|
||||||
const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize(), animPath.getOriginalName());
|
const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize(), path.getOriginalName());
|
||||||
|
|
||||||
initFromJson(result, config);
|
initFromJson(result, config, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto & g : result)
|
|
||||||
for(auto & i : g.second)
|
|
||||||
i.preScaledFactor = tmp.second;
|
|
||||||
|
|
||||||
animationLayouts[actualPath] = result;
|
animationLayouts[actualPath] = result;
|
||||||
return animationLayouts[actualPath];
|
return animationLayouts[actualPath];
|
||||||
}
|
}
|
||||||
@ -202,209 +157,170 @@ int RenderHandler::getScalingFactor() const
|
|||||||
return GH.screenHandler().getScalingFactor();
|
return GH.screenHandler().getScalingFactor();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageLocator RenderHandler::getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group)
|
ImageLocator RenderHandler::getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
|
||||||
{
|
{
|
||||||
const auto & layout = getAnimationLayout(path);
|
const auto & layout = getAnimationLayout(path, 1, mode);
|
||||||
if (!layout.count(group))
|
if (!layout.count(group))
|
||||||
return ImageLocator(ImagePath::builtin("DEFAULT"));
|
return ImageLocator(ImagePath::builtin("DEFAULT"), mode);
|
||||||
|
|
||||||
if (frame >= layout.at(group).size())
|
if (frame >= layout.at(group).size())
|
||||||
return ImageLocator(ImagePath::builtin("DEFAULT"));
|
return ImageLocator(ImagePath::builtin("DEFAULT"), mode);
|
||||||
|
|
||||||
const auto & locator = layout.at(group).at(frame);
|
const auto & locator = layout.at(group).at(frame);
|
||||||
if (locator.image || locator.defFile)
|
if (locator.image || locator.defFile)
|
||||||
return locator;
|
return locator;
|
||||||
|
|
||||||
return ImageLocator(path, frame, group);
|
return ImageLocator(path, frame, group, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> RenderHandler::loadImageImpl(const ImageLocator & locator)
|
std::shared_ptr<ScalableImageShared> RenderHandler::loadImageImpl(const ImageLocator & locator)
|
||||||
{
|
{
|
||||||
auto it = imageFiles.find(locator);
|
auto it = imageFiles.find(locator);
|
||||||
if (it != imageFiles.end())
|
if (it != imageFiles.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
// TODO: order should be different:
|
auto sdlImage = loadImageFromFileUncached(locator);
|
||||||
// 1) try to find correctly scaled image
|
auto scaledImage = std::make_shared<ScalableImageShared>(locator, sdlImage);
|
||||||
// 2) if fails -> try to find correctly transformed
|
|
||||||
// 3) if also fails -> try to find image from correct file
|
|
||||||
// 4) load missing part of the sequence
|
|
||||||
// TODO: check whether (load -> transform -> scale) or (load -> scale -> transform) order should be used for proper loading of pre-scaled data
|
|
||||||
auto imageFromFile = loadImageFromFile(locator.copyFile());
|
|
||||||
auto transformedImage = transformImage(locator.copyFileTransform(), imageFromFile);
|
|
||||||
auto scaledImage = scaleImage(locator.copyFileTransformScale(), transformedImage);
|
|
||||||
|
|
||||||
|
storeCachedImage(locator, scaledImage);
|
||||||
return scaledImage;
|
return scaledImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> RenderHandler::loadImageFromFileUncached(const ImageLocator & locator)
|
std::shared_ptr<SDLImageShared> RenderHandler::loadImageFromFileUncached(const ImageLocator & locator)
|
||||||
{
|
{
|
||||||
if(locator.image)
|
if(locator.image)
|
||||||
{
|
{
|
||||||
// TODO: create EmptySharedImage class that will be instantiated if image does not exists or fails to load
|
// TODO: create EmptySharedImage class that will be instantiated if image does not exists or fails to load
|
||||||
return std::make_shared<SDLImageShared>(*locator.image, locator.preScaledFactor);
|
return std::make_shared<SDLImageShared>(*locator.image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(locator.defFile)
|
if(locator.defFile)
|
||||||
{
|
{
|
||||||
auto defFile = getAnimationFile(*locator.defFile);
|
auto defFile = getAnimationFile(*locator.defFile);
|
||||||
int preScaledFactor = locator.preScaledFactor;
|
|
||||||
if(!defFile) // no prescale for this frame
|
|
||||||
{
|
|
||||||
auto tmpPath = (*locator.defFile).getName();
|
|
||||||
boost::algorithm::replace_all(tmpPath, "SPRITES2X/", "SPRITES/");
|
|
||||||
boost::algorithm::replace_all(tmpPath, "SPRITES3X/", "SPRITES/");
|
|
||||||
boost::algorithm::replace_all(tmpPath, "SPRITES4X/", "SPRITES/");
|
|
||||||
preScaledFactor = 1;
|
|
||||||
defFile = getAnimationFile(AnimationPath::builtin(tmpPath));
|
|
||||||
}
|
|
||||||
if(defFile->hasFrame(locator.defFrame, locator.defGroup))
|
if(defFile->hasFrame(locator.defFrame, locator.defGroup))
|
||||||
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup, preScaledFactor);
|
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logGlobal->error("Frame %d in group %d not found in file: %s",
|
logGlobal->error("Frame %d in group %d not found in file: %s",
|
||||||
locator.defFrame, locator.defGroup, locator.defFile->getName().c_str());
|
locator.defFrame, locator.defGroup, locator.defFile->getName().c_str());
|
||||||
return std::make_shared<SDLImageShared>(ImagePath::builtin("DEFAULT"), locator.preScaledFactor);
|
return std::make_shared<SDLImageShared>(ImagePath::builtin("DEFAULT"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Invalid image locator received!");
|
throw std::runtime_error("Invalid image locator received!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderHandler::storeCachedImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image)
|
void RenderHandler::storeCachedImage(const ImageLocator & locator, std::shared_ptr<ScalableImageShared> image)
|
||||||
{
|
{
|
||||||
imageFiles[locator] = image;
|
imageFiles[locator] = image;
|
||||||
|
|
||||||
#if 0
|
|
||||||
const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "imageCache" / (locator.toString() + ".png");
|
|
||||||
boost::filesystem::path outDir = outPath;
|
|
||||||
outDir.remove_filename();
|
|
||||||
boost::filesystem::create_directories(outDir);
|
|
||||||
image->exportBitmap(outPath , nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> RenderHandler::loadImageFromFile(const ImageLocator & locator)
|
std::shared_ptr<SDLImageShared> RenderHandler::loadSingleImage(const ImageLocator & locator)
|
||||||
{
|
{
|
||||||
if (imageFiles.count(locator))
|
assert(locator.scalingFactor != 0);
|
||||||
return imageFiles.at(locator);
|
|
||||||
|
|
||||||
auto result = loadImageFromFileUncached(locator);
|
static constexpr std::array scaledDataPath = {
|
||||||
storeCachedImage(locator, result);
|
"", // 0x
|
||||||
return result;
|
"DATA/",
|
||||||
}
|
"DATA2X/",
|
||||||
|
"DATA3X/",
|
||||||
|
"DATA4X/",
|
||||||
|
};
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> RenderHandler::transformImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image)
|
static constexpr std::array scaledSpritesPath = {
|
||||||
|
"", // 0x
|
||||||
|
"SPRITES/",
|
||||||
|
"SPRITES2X/",
|
||||||
|
"SPRITES3X/",
|
||||||
|
"SPRITES4X/",
|
||||||
|
};
|
||||||
|
|
||||||
|
if(locator.image)
|
||||||
{
|
{
|
||||||
if (imageFiles.count(locator))
|
std::string imagePathString = locator.image->getName();
|
||||||
return imageFiles.at(locator);
|
|
||||||
|
|
||||||
auto result = image;
|
if(locator.layer == EImageBlitMode::ONLY_OVERLAY)
|
||||||
|
imagePathString += "-OVERLAY";
|
||||||
|
if(locator.layer == EImageBlitMode::ONLY_SHADOW)
|
||||||
|
imagePathString += "-SHADOW";
|
||||||
|
|
||||||
if (locator.verticalFlip)
|
auto imagePath = ImagePath::builtin(imagePathString);
|
||||||
result = result->verticalFlip();
|
auto imagePathSprites = ImagePath::builtin(imagePathString).addPrefix(scaledSpritesPath.at(locator.scalingFactor));
|
||||||
|
auto imagePathData = ImagePath::builtin(imagePathString).addPrefix(scaledDataPath.at(locator.scalingFactor));
|
||||||
|
|
||||||
if (locator.horizontalFlip)
|
if(CResourceHandler::get()->existsResource(imagePathSprites))
|
||||||
result = result->horizontalFlip();
|
return std::make_shared<SDLImageShared>(imagePathSprites);
|
||||||
|
|
||||||
storeCachedImage(locator, result);
|
if(CResourceHandler::get()->existsResource(imagePathData))
|
||||||
return result;
|
return std::make_shared<SDLImageShared>(imagePathData);
|
||||||
|
|
||||||
|
if(CResourceHandler::get()->existsResource(imagePath))
|
||||||
|
return std::make_shared<SDLImageShared>(imagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> RenderHandler::scaleImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image)
|
if(locator.defFile)
|
||||||
{
|
{
|
||||||
if (imageFiles.count(locator))
|
AnimationPath defFilePath = locator.defFile->addPrefix(scaledSpritesPath.at(locator.scalingFactor));
|
||||||
return imageFiles.at(locator);
|
auto defFile = getAnimationFile(defFilePath);
|
||||||
|
|
||||||
auto handle = image->createImageReference(locator.layer);
|
if(defFile && defFile->hasFrame(locator.defFrame, locator.defGroup))
|
||||||
|
{
|
||||||
assert(locator.scalingFactor != 1); // should be filtered-out before
|
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup);
|
||||||
if (locator.playerColored != PlayerColor::CANNOT_DETERMINE)
|
}
|
||||||
handle->playerColored(locator.playerColored);
|
|
||||||
|
|
||||||
handle->scaleInteger(locator.scalingFactor);
|
|
||||||
|
|
||||||
auto result = handle->getSharedImage();
|
|
||||||
storeCachedImage(locator, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator, EImageBlitMode mode)
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator)
|
||||||
{
|
{
|
||||||
ImageLocator adjustedLocator = locator;
|
ImageLocator adjustedLocator = locator;
|
||||||
|
|
||||||
if(adjustedLocator.image)
|
std::shared_ptr<ScalableImageInstance> result;
|
||||||
{
|
|
||||||
std::string imgPath = (*adjustedLocator.image).getName();
|
|
||||||
if(adjustedLocator.layer == EImageBlitMode::ONLY_OVERLAY)
|
|
||||||
imgPath += "-OVERLAY";
|
|
||||||
if(adjustedLocator.layer == EImageBlitMode::ONLY_SHADOW)
|
|
||||||
imgPath += "-SHADOW";
|
|
||||||
|
|
||||||
if(CResourceHandler::get()->existsResource(ImagePath::builtin(imgPath)) ||
|
|
||||||
CResourceHandler::get()->existsResource(ImagePath::builtin(imgPath).addPrefix("DATA/")) ||
|
|
||||||
CResourceHandler::get()->existsResource(ImagePath::builtin(imgPath).addPrefix("SPRITES/")))
|
|
||||||
adjustedLocator.image = ImagePath::builtin(imgPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(adjustedLocator.defFile && adjustedLocator.scalingFactor == 0)
|
|
||||||
{
|
|
||||||
auto tmp = getScalePath(*adjustedLocator.defFile);
|
|
||||||
adjustedLocator.defFile = AnimationPath::builtin(tmp.first.getName());
|
|
||||||
adjustedLocator.preScaledFactor = tmp.second;
|
|
||||||
}
|
|
||||||
if(adjustedLocator.image && adjustedLocator.scalingFactor == 0)
|
|
||||||
{
|
|
||||||
auto tmp = getScalePath(*adjustedLocator.image);
|
|
||||||
adjustedLocator.image = ImagePath::builtin(tmp.first.getName());
|
|
||||||
adjustedLocator.preScaledFactor = tmp.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adjustedLocator.scalingFactor == 0 && getScalingFactor() != 1 )
|
|
||||||
{
|
|
||||||
auto unscaledLocator = adjustedLocator;
|
|
||||||
auto scaledLocator = adjustedLocator;
|
|
||||||
|
|
||||||
unscaledLocator.scalingFactor = 1;
|
|
||||||
scaledLocator.scalingFactor = getScalingFactor();
|
|
||||||
auto unscaledImage = loadImageImpl(unscaledLocator);
|
|
||||||
|
|
||||||
return std::make_shared<ImageScaled>(scaledLocator, unscaledImage, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adjustedLocator.scalingFactor == 0)
|
if (adjustedLocator.scalingFactor == 0)
|
||||||
{
|
{
|
||||||
auto scaledLocator = adjustedLocator;
|
auto scaledLocator = adjustedLocator;
|
||||||
scaledLocator.scalingFactor = getScalingFactor();
|
scaledLocator.scalingFactor = getScalingFactor();
|
||||||
|
|
||||||
return loadImageImpl(scaledLocator)->createImageReference(mode);
|
result = loadImageImpl(scaledLocator)->createImageReference();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return loadImageImpl(adjustedLocator)->createImageReference(mode);
|
result = loadImageImpl(adjustedLocator)->createImageReference();
|
||||||
|
|
||||||
|
if (locator.horizontalFlip)
|
||||||
|
result->horizontalFlip();
|
||||||
|
if (locator.verticalFlip)
|
||||||
|
result->verticalFlip();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
|
std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
|
||||||
{
|
{
|
||||||
auto tmp = getScalePath(path);
|
ImageLocator locator = getLocatorForAnimationFrame(path, frame, group, mode);
|
||||||
ImageLocator locator = getLocatorForAnimationFrame(AnimationPath::builtin(tmp.first.getName()), frame, group);
|
return loadImage(locator);
|
||||||
locator.preScaledFactor = tmp.second;
|
|
||||||
return loadImage(locator, mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
|
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
|
||||||
{
|
{
|
||||||
ImageLocator locator(path);
|
ImageLocator locator(path, mode);
|
||||||
return loadImage(locator, mode);
|
return loadImage(locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
|
std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
|
||||||
{
|
{
|
||||||
return std::make_shared<SDLImageShared>(source)->createImageReference(EImageBlitMode::SIMPLE);
|
auto baseImage = std::make_shared<SDLImageShared>(source);
|
||||||
|
SharedImageLocator locator;
|
||||||
|
locator.layer = EImageBlitMode::SIMPLE;
|
||||||
|
auto scalableImage = std::make_shared<ScalableImageShared>(locator, baseImage);
|
||||||
|
|
||||||
|
return scalableImage->createImageReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)
|
std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)
|
||||||
{
|
{
|
||||||
return std::make_shared<CAnimation>(path, getAnimationLayout(path), mode);
|
return std::make_shared<CAnimation>(path, getAnimationLayout(path, 1, mode), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderHandler::addImageListEntries(const EntityService * service)
|
void RenderHandler::addImageListEntries(const EntityService * service)
|
||||||
@ -416,7 +332,7 @@ void RenderHandler::addImageListEntries(const EntityService * service)
|
|||||||
if (imageName.empty())
|
if (imageName.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName));
|
auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName), 1, EImageBlitMode::SIMPLE);
|
||||||
|
|
||||||
JsonNode entry;
|
JsonNode entry;
|
||||||
entry["file"].String() = imageName;
|
entry["file"].String() = imageName;
|
||||||
@ -424,7 +340,7 @@ void RenderHandler::addImageListEntries(const EntityService * service)
|
|||||||
if (index >= layout[group].size())
|
if (index >= layout[group].size())
|
||||||
layout[group].resize(index + 1);
|
layout[group].resize(index + 1);
|
||||||
|
|
||||||
layout[group][index] = ImageLocator(entry);
|
layout[group][index] = ImageLocator(entry, EImageBlitMode::SIMPLE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ VCMI_LIB_NAMESPACE_END
|
|||||||
|
|
||||||
class CDefFile;
|
class CDefFile;
|
||||||
class SDLImageShared;
|
class SDLImageShared;
|
||||||
class ISharedImage;
|
class ScalableImageShared;
|
||||||
|
|
||||||
class RenderHandler : public IRenderHandler
|
class RenderHandler : public IRenderHandler
|
||||||
{
|
{
|
||||||
@ -25,28 +25,22 @@ class RenderHandler : public IRenderHandler
|
|||||||
|
|
||||||
std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
|
std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
|
||||||
std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
|
std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
|
||||||
std::map<ImageLocator, std::shared_ptr<const ISharedImage>> imageFiles;
|
std::map<SharedImageLocator, std::shared_ptr<ScalableImageShared>> imageFiles;
|
||||||
std::map<EFonts, std::shared_ptr<const IFont>> fonts;
|
std::map<EFonts, std::shared_ptr<const IFont>> fonts;
|
||||||
|
|
||||||
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
|
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
|
||||||
std::optional<ResourcePath> getPathForScaleFactor(const ResourcePath & path, const std::string & factor);
|
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path, int scalingFactor, EImageBlitMode mode);
|
||||||
std::pair<ResourcePath, int> getScalePath(const ResourcePath & p);
|
void initFromJson(AnimationLayoutMap & layout, const JsonNode & config, EImageBlitMode mode);
|
||||||
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
|
|
||||||
void initFromJson(AnimationLayoutMap & layout, const JsonNode & config);
|
|
||||||
|
|
||||||
void addImageListEntry(size_t index, size_t group, const std::string & listName, const std::string & imageName);
|
void addImageListEntry(size_t index, size_t group, const std::string & listName, const std::string & imageName);
|
||||||
void addImageListEntries(const EntityService * service);
|
void addImageListEntries(const EntityService * service);
|
||||||
void storeCachedImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image);
|
void storeCachedImage(const ImageLocator & locator, std::shared_ptr<ScalableImageShared> image);
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> loadImageImpl(const ImageLocator & config);
|
std::shared_ptr<ScalableImageShared> loadImageImpl(const ImageLocator & config);
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> loadImageFromFileUncached(const ImageLocator & locator);
|
std::shared_ptr<SDLImageShared> loadImageFromFileUncached(const ImageLocator & locator);
|
||||||
std::shared_ptr<const ISharedImage> loadImageFromFile(const ImageLocator & locator);
|
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> transformImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image);
|
ImageLocator getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group, EImageBlitMode mode);
|
||||||
std::shared_ptr<const ISharedImage> scaleImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image);
|
|
||||||
|
|
||||||
ImageLocator getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group);
|
|
||||||
|
|
||||||
int getScalingFactor() const;
|
int getScalingFactor() const;
|
||||||
|
|
||||||
@ -55,10 +49,12 @@ public:
|
|||||||
// IRenderHandler implementation
|
// IRenderHandler implementation
|
||||||
void onLibraryLoadingFinished(const Services * services) override;
|
void onLibraryLoadingFinished(const Services * services) override;
|
||||||
|
|
||||||
std::shared_ptr<IImage> loadImage(const ImageLocator & locator, EImageBlitMode mode) override;
|
std::shared_ptr<IImage> loadImage(const ImageLocator & locator) override;
|
||||||
std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) override;
|
std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) override;
|
||||||
std::shared_ptr<IImage> loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode) override;
|
std::shared_ptr<IImage> loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode) override;
|
||||||
|
|
||||||
|
std::shared_ptr<SDLImageShared> loadSingleImage(const ImageLocator & locator) override;
|
||||||
|
|
||||||
std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) override;
|
std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) override;
|
||||||
|
|
||||||
std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
|
std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
|
||||||
|
@ -28,59 +28,6 @@
|
|||||||
|
|
||||||
class SDLImageLoader;
|
class SDLImageLoader;
|
||||||
|
|
||||||
//First 8 colors in def palette used for transparency
|
|
||||||
static constexpr std::array<SDL_Color, 8> sourcePalette = {{
|
|
||||||
{0, 255, 255, SDL_ALPHA_OPAQUE},
|
|
||||||
{255, 150, 255, SDL_ALPHA_OPAQUE},
|
|
||||||
{255, 100, 255, SDL_ALPHA_OPAQUE},
|
|
||||||
{255, 50, 255, SDL_ALPHA_OPAQUE},
|
|
||||||
{255, 0, 255, SDL_ALPHA_OPAQUE},
|
|
||||||
{255, 255, 0, SDL_ALPHA_OPAQUE},
|
|
||||||
{180, 0, 255, SDL_ALPHA_OPAQUE},
|
|
||||||
{0, 255, 0, SDL_ALPHA_OPAQUE}
|
|
||||||
}};
|
|
||||||
|
|
||||||
static constexpr std::array<ColorRGBA, 8> targetPalette = {{
|
|
||||||
{0, 0, 0, 0 }, // 0 - transparency ( used in most images )
|
|
||||||
{0, 0, 0, 64 }, // 1 - shadow border ( used in battle, adventure map def's )
|
|
||||||
{0, 0, 0, 64 }, // 2 - shadow border ( used in fog-of-war def's )
|
|
||||||
{0, 0, 0, 128}, // 3 - shadow body ( used in fog-of-war def's )
|
|
||||||
{0, 0, 0, 128}, // 4 - shadow body ( used in battle, adventure map def's )
|
|
||||||
{0, 0, 0, 0 }, // 5 - selection / owner flag ( used in battle, adventure map def's )
|
|
||||||
{0, 0, 0, 128}, // 6 - shadow body below selection ( used in battle def's )
|
|
||||||
{0, 0, 0, 64 } // 7 - shadow border below selection ( used in battle def's )
|
|
||||||
}};
|
|
||||||
|
|
||||||
static ui8 mixChannels(ui8 c1, ui8 c2, ui8 a1, ui8 a2)
|
|
||||||
{
|
|
||||||
return c1*a1 / 256 + c2*a2*(255 - a1) / 256 / 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ColorRGBA addColors(const ColorRGBA & base, const ColorRGBA & over)
|
|
||||||
{
|
|
||||||
return ColorRGBA(
|
|
||||||
mixChannels(over.r, base.r, over.a, base.a),
|
|
||||||
mixChannels(over.g, base.g, over.a, base.a),
|
|
||||||
mixChannels(over.b, base.b, over.a, base.a),
|
|
||||||
static_cast<ui8>(over.a + base.a * (255 - over.a) / 256)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool colorsSimilar (const SDL_Color & lhs, const SDL_Color & rhs)
|
|
||||||
{
|
|
||||||
// it seems that H3 does not requires exact match to replace colors -> (255, 103, 255) gets interpreted as shadow
|
|
||||||
// exact logic is not clear and requires extensive testing with image editing
|
|
||||||
// potential reason is that H3 uses 16-bit color format (565 RGB bits), meaning that 3 least significant bits are lost in red and blue component
|
|
||||||
static const int threshold = 8;
|
|
||||||
|
|
||||||
int diffR = static_cast<int>(lhs.r) - rhs.r;
|
|
||||||
int diffG = static_cast<int>(lhs.g) - rhs.g;
|
|
||||||
int diffB = static_cast<int>(lhs.b) - rhs.b;
|
|
||||||
int diffA = static_cast<int>(lhs.a) - rhs.a;
|
|
||||||
|
|
||||||
return std::abs(diffR) < threshold && std::abs(diffG) < threshold && std::abs(diffB) < threshold && std::abs(diffA) < threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
int IImage::width() const
|
int IImage::width() const
|
||||||
{
|
{
|
||||||
return dimensions().x;
|
return dimensions().x;
|
||||||
@ -91,12 +38,11 @@ int IImage::height() const
|
|||||||
return dimensions().y;
|
return dimensions().y;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group, int preScaleFactor)
|
SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group)
|
||||||
: surf(nullptr),
|
: surf(nullptr),
|
||||||
margins(0, 0),
|
margins(0, 0),
|
||||||
fullSize(0, 0),
|
fullSize(0, 0),
|
||||||
originalPalette(nullptr),
|
originalPalette(nullptr)
|
||||||
preScaleFactor(preScaleFactor)
|
|
||||||
{
|
{
|
||||||
SDLImageLoader loader(this);
|
SDLImageLoader loader(this);
|
||||||
data->loadFrame(frame, group, loader);
|
data->loadFrame(frame, group, loader);
|
||||||
@ -104,12 +50,11 @@ SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group
|
|||||||
savePalette();
|
savePalette();
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLImageShared::SDLImageShared(SDL_Surface * from, int preScaleFactor)
|
SDLImageShared::SDLImageShared(SDL_Surface * from)
|
||||||
: surf(nullptr),
|
: surf(nullptr),
|
||||||
margins(0, 0),
|
margins(0, 0),
|
||||||
fullSize(0, 0),
|
fullSize(0, 0),
|
||||||
originalPalette(nullptr),
|
originalPalette(nullptr)
|
||||||
preScaleFactor(preScaleFactor)
|
|
||||||
{
|
{
|
||||||
surf = from;
|
surf = from;
|
||||||
if (surf == nullptr)
|
if (surf == nullptr)
|
||||||
@ -122,12 +67,11 @@ SDLImageShared::SDLImageShared(SDL_Surface * from, int preScaleFactor)
|
|||||||
fullSize.y = surf->h;
|
fullSize.y = surf->h;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLImageShared::SDLImageShared(const ImagePath & filename, int preScaleFactor)
|
SDLImageShared::SDLImageShared(const ImagePath & filename)
|
||||||
: surf(nullptr),
|
: surf(nullptr),
|
||||||
margins(0, 0),
|
margins(0, 0),
|
||||||
fullSize(0, 0),
|
fullSize(0, 0),
|
||||||
originalPalette(nullptr),
|
originalPalette(nullptr)
|
||||||
preScaleFactor(preScaleFactor)
|
|
||||||
{
|
{
|
||||||
surf = BitmapHandler::loadBitmap(filename);
|
surf = BitmapHandler::loadBitmap(filename);
|
||||||
|
|
||||||
@ -146,7 +90,6 @@ SDLImageShared::SDLImageShared(const ImagePath & filename, int preScaleFactor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SDLImageShared::draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const
|
void SDLImageShared::draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const
|
||||||
{
|
{
|
||||||
if (!surf)
|
if (!surf)
|
||||||
@ -292,26 +235,20 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL
|
|||||||
SDL_SetSurfacePalette(surf, palette);
|
SDL_SetSurfacePalette(surf, palette);
|
||||||
|
|
||||||
SDL_Surface * scaled = nullptr;
|
SDL_Surface * scaled = nullptr;
|
||||||
if(preScaleFactor == factor)
|
|
||||||
return shared_from_this();
|
|
||||||
else if(preScaleFactor == 1)
|
|
||||||
{
|
|
||||||
// dump heuristics to differentiate tileable UI elements from map object / combat assets
|
// dump heuristics to differentiate tileable UI elements from map object / combat assets
|
||||||
if (mode == EImageBlitMode::OPAQUE || mode == EImageBlitMode::COLORKEY || mode == EImageBlitMode::SIMPLE)
|
if (mode == EImageBlitMode::OPAQUE || mode == EImageBlitMode::COLORKEY || mode == EImageBlitMode::SIMPLE)
|
||||||
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_OPAQUE);
|
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_OPAQUE);
|
||||||
else
|
else
|
||||||
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_ALPHA);
|
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_ALPHA);
|
||||||
}
|
|
||||||
else
|
|
||||||
scaled = CSDL_Ext::scaleSurface(surf, (int) round((float)surf->w * factor / preScaleFactor), (int) round((float)surf->h * factor / preScaleFactor));
|
|
||||||
|
|
||||||
auto ret = std::make_shared<SDLImageShared>(scaled, preScaleFactor);
|
auto ret = std::make_shared<SDLImageShared>(scaled);
|
||||||
|
|
||||||
ret->fullSize.x = fullSize.x * factor;
|
ret->fullSize.x = fullSize.x * factor;
|
||||||
ret->fullSize.y = fullSize.y * factor;
|
ret->fullSize.y = fullSize.y * factor;
|
||||||
|
|
||||||
ret->margins.x = (int) round((float)margins.x * factor / preScaleFactor);
|
ret->margins.x = (int) round((float)margins.x * factor);
|
||||||
ret->margins.y = (int) round((float)margins.y * factor / preScaleFactor);
|
ret->margins.y = (int) round((float)margins.y * factor);
|
||||||
ret->optimizeSurface();
|
ret->optimizeSurface();
|
||||||
|
|
||||||
// erase our own reference
|
// erase our own reference
|
||||||
@ -340,7 +277,7 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size,
|
|||||||
else
|
else
|
||||||
CSDL_Ext::setDefaultColorKey(scaled);//just in case
|
CSDL_Ext::setDefaultColorKey(scaled);//just in case
|
||||||
|
|
||||||
auto ret = std::make_shared<SDLImageShared>(scaled, preScaleFactor);
|
auto ret = std::make_shared<SDLImageShared>(scaled);
|
||||||
|
|
||||||
ret->fullSize.x = (int) round((float)fullSize.x * scaleX);
|
ret->fullSize.x = (int) round((float)fullSize.x * scaleX);
|
||||||
ret->fullSize.y = (int) round((float)fullSize.y * scaleY);
|
ret->fullSize.y = (int) round((float)fullSize.y * scaleY);
|
||||||
@ -369,11 +306,6 @@ void SDLImageShared::exportBitmap(const boost::filesystem::path& path, SDL_Palet
|
|||||||
SDL_SetSurfacePalette(surf, originalPalette);
|
SDL_SetSurfacePalette(surf, originalPalette);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLImageIndexed::playerColored(PlayerColor player)
|
|
||||||
{
|
|
||||||
graphics->setPlayerPalette(currentPalette, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLImageShared::isTransparent(const Point & coords) const
|
bool SDLImageShared::isTransparent(const Point & coords) const
|
||||||
{
|
{
|
||||||
if (surf)
|
if (surf)
|
||||||
@ -384,22 +316,21 @@ bool SDLImageShared::isTransparent(const Point & coords) const
|
|||||||
|
|
||||||
Rect SDLImageShared::contentRect() const
|
Rect SDLImageShared::contentRect() const
|
||||||
{
|
{
|
||||||
auto tmpMargins = margins / preScaleFactor;
|
auto tmpMargins = margins;
|
||||||
auto tmpSize = Point(surf->w, surf->h) / preScaleFactor;
|
auto tmpSize = Point(surf->w, surf->h);
|
||||||
return Rect(tmpMargins, tmpSize);
|
return Rect(tmpMargins, tmpSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SDL_Palette * SDLImageShared::getPalette() const
|
||||||
|
{
|
||||||
|
if (!surf)
|
||||||
|
return nullptr;
|
||||||
|
return surf->format->palette;
|
||||||
|
}
|
||||||
|
|
||||||
Point SDLImageShared::dimensions() const
|
Point SDLImageShared::dimensions() const
|
||||||
{
|
{
|
||||||
return fullSize / preScaleFactor;
|
return fullSize;
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IImage> SDLImageShared::createImageReference(EImageBlitMode mode) const
|
|
||||||
{
|
|
||||||
if (surf && surf->format->palette)
|
|
||||||
return std::make_shared<SDLImageIndexed>(shared_from_this(), originalPalette, mode);
|
|
||||||
else
|
|
||||||
return std::make_shared<SDLImageRGB>(shared_from_this(), mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> SDLImageShared::horizontalFlip() const
|
std::shared_ptr<const ISharedImage> SDLImageShared::horizontalFlip() const
|
||||||
@ -408,7 +339,7 @@ std::shared_ptr<const ISharedImage> SDLImageShared::horizontalFlip() const
|
|||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
|
|
||||||
SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf);
|
SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf);
|
||||||
auto ret = std::make_shared<SDLImageShared>(flipped, preScaleFactor);
|
auto ret = std::make_shared<SDLImageShared>(flipped);
|
||||||
ret->fullSize = fullSize;
|
ret->fullSize = fullSize;
|
||||||
ret->margins.x = margins.x;
|
ret->margins.x = margins.x;
|
||||||
ret->margins.y = fullSize.y - surf->h - margins.y;
|
ret->margins.y = fullSize.y - surf->h - margins.y;
|
||||||
@ -423,7 +354,7 @@ std::shared_ptr<const ISharedImage> SDLImageShared::verticalFlip() const
|
|||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
|
|
||||||
SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf);
|
SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf);
|
||||||
auto ret = std::make_shared<SDLImageShared>(flipped, preScaleFactor);
|
auto ret = std::make_shared<SDLImageShared>(flipped);
|
||||||
ret->fullSize = fullSize;
|
ret->fullSize = fullSize;
|
||||||
ret->margins.x = fullSize.x - surf->w - margins.x;
|
ret->margins.x = fullSize.x - surf->w - margins.x;
|
||||||
ret->margins.y = margins.y;
|
ret->margins.y = margins.y;
|
||||||
@ -445,219 +376,8 @@ void SDLImageShared::savePalette()
|
|||||||
SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, surf->format->palette->ncolors);
|
SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, surf->format->palette->ncolors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLImageIndexed::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
|
|
||||||
{
|
|
||||||
std::vector<SDL_Color> shifterColors(colorsToMove);
|
|
||||||
|
|
||||||
for(uint32_t i=0; i<colorsToMove; ++i)
|
|
||||||
shifterColors[(i+distanceToMove)%colorsToMove] = originalPalette->colors[firstColorID + i];
|
|
||||||
|
|
||||||
SDL_SetPaletteColors(currentPalette, shifterColors.data(), firstColorID, colorsToMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask)
|
|
||||||
{
|
|
||||||
// If shadow is enabled, following colors must be skipped unconditionally
|
|
||||||
if (blitMode == EImageBlitMode::WITH_SHADOW || blitMode == EImageBlitMode::WITH_SHADOW_AND_OVERLAY)
|
|
||||||
colorsToSkipMask |= (1 << 0) + (1 << 1) + (1 << 4);
|
|
||||||
|
|
||||||
// Note: here we skip first colors in the palette that are predefined in H3 images
|
|
||||||
for(int i = 0; i < currentPalette->ncolors; i++)
|
|
||||||
{
|
|
||||||
if (i < std::size(sourcePalette) && colorsSimilar(sourcePalette[i], originalPalette->colors[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(i < std::numeric_limits<uint32_t>::digits && ((colorsToSkipMask >> i) & 1) == 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
currentPalette->colors[i] = CSDL_Ext::toSDL(shifter.shiftColor(CSDL_Ext::fromSDL(originalPalette->colors[i])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDLImageIndexed::SDLImageIndexed(const std::shared_ptr<const ISharedImage> & image, SDL_Palette * originalPalette, EImageBlitMode mode)
|
|
||||||
:SDLImageBase::SDLImageBase(image, mode)
|
|
||||||
,originalPalette(originalPalette)
|
|
||||||
{
|
|
||||||
currentPalette = SDL_AllocPalette(originalPalette->ncolors);
|
|
||||||
SDL_SetPaletteColors(currentPalette, originalPalette->colors, 0, originalPalette->ncolors);
|
|
||||||
|
|
||||||
preparePalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
SDLImageIndexed::~SDLImageIndexed()
|
|
||||||
{
|
|
||||||
SDL_FreePalette(currentPalette);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::setShadowTransparency(float factor)
|
|
||||||
{
|
|
||||||
ColorRGBA shadow50(0, 0, 0, 128 * factor);
|
|
||||||
ColorRGBA shadow25(0, 0, 0, 64 * factor);
|
|
||||||
|
|
||||||
std::array<SDL_Color, 5> colorsSDL = {
|
|
||||||
originalPalette->colors[0],
|
|
||||||
originalPalette->colors[1],
|
|
||||||
originalPalette->colors[2],
|
|
||||||
originalPalette->colors[3],
|
|
||||||
originalPalette->colors[4]
|
|
||||||
};
|
|
||||||
|
|
||||||
// seems to be used unconditionally
|
|
||||||
colorsSDL[0] = CSDL_Ext::toSDL(Colors::TRANSPARENCY);
|
|
||||||
colorsSDL[1] = CSDL_Ext::toSDL(shadow25);
|
|
||||||
colorsSDL[4] = CSDL_Ext::toSDL(shadow50);
|
|
||||||
|
|
||||||
// seems to be used only if color matches
|
|
||||||
if (colorsSimilar(originalPalette->colors[2], sourcePalette[2]))
|
|
||||||
colorsSDL[2] = CSDL_Ext::toSDL(shadow25);
|
|
||||||
|
|
||||||
if (colorsSimilar(originalPalette->colors[3], sourcePalette[3]))
|
|
||||||
colorsSDL[3] = CSDL_Ext::toSDL(shadow50);
|
|
||||||
|
|
||||||
SDL_SetPaletteColors(currentPalette, colorsSDL.data(), 0, colorsSDL.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::setOverlayColor(const ColorRGBA & color)
|
|
||||||
{
|
|
||||||
currentPalette->colors[5] = CSDL_Ext::toSDL(addColors(targetPalette[5], color));
|
|
||||||
|
|
||||||
for (int i : {6,7})
|
|
||||||
{
|
|
||||||
if (colorsSimilar(originalPalette->colors[i], sourcePalette[i]))
|
|
||||||
currentPalette->colors[i] = CSDL_Ext::toSDL(addColors(targetPalette[i], color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::preparePalette()
|
|
||||||
{
|
|
||||||
switch(blitMode)
|
|
||||||
{
|
|
||||||
case EImageBlitMode::ONLY_SHADOW:
|
|
||||||
case EImageBlitMode::ONLY_OVERLAY:
|
|
||||||
adjustPalette(ColorFilter::genAlphaShifter(0), 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(blitMode)
|
|
||||||
{
|
|
||||||
case EImageBlitMode::SIMPLE:
|
|
||||||
case EImageBlitMode::WITH_SHADOW:
|
|
||||||
case EImageBlitMode::ONLY_SHADOW:
|
|
||||||
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
|
||||||
setShadowTransparency(1.0);
|
|
||||||
break;
|
|
||||||
case EImageBlitMode::ONLY_BODY:
|
|
||||||
case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
|
|
||||||
case EImageBlitMode::ONLY_OVERLAY:
|
|
||||||
setShadowTransparency(0.0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(blitMode)
|
|
||||||
{
|
|
||||||
case EImageBlitMode::ONLY_OVERLAY:
|
|
||||||
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
|
||||||
setOverlayColor(Colors::WHITE_TRUE);
|
|
||||||
break;
|
|
||||||
case EImageBlitMode::ONLY_SHADOW:
|
|
||||||
case EImageBlitMode::ONLY_BODY:
|
|
||||||
setOverlayColor(Colors::TRANSPARENCY);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDLImageShared::~SDLImageShared()
|
SDLImageShared::~SDLImageShared()
|
||||||
{
|
{
|
||||||
SDL_FreeSurface(surf);
|
SDL_FreeSurface(surf);
|
||||||
SDL_FreePalette(originalPalette);
|
SDL_FreePalette(originalPalette);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLImageBase::SDLImageBase(const std::shared_ptr<const ISharedImage> & image, EImageBlitMode mode)
|
|
||||||
:image(image)
|
|
||||||
, alphaValue(SDL_ALPHA_OPAQUE)
|
|
||||||
, blitMode(mode)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::shared_ptr<const ISharedImage> SDLImageBase::getSharedImage() const
|
|
||||||
{
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageRGB::draw(SDL_Surface * where, const Point & pos, const Rect * src) const
|
|
||||||
{
|
|
||||||
image->draw(where, nullptr, pos, src, Colors::WHITE_TRUE, alphaValue, blitMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::draw(SDL_Surface * where, const Point & pos, const Rect * src) const
|
|
||||||
{
|
|
||||||
image->draw(where, currentPalette, pos, src, Colors::WHITE_TRUE, alphaValue, blitMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::exportBitmap(const boost::filesystem::path & path) const
|
|
||||||
{
|
|
||||||
image->exportBitmap(path, currentPalette);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::scaleTo(const Point & size)
|
|
||||||
{
|
|
||||||
image = image->scaleTo(size, currentPalette);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageRGB::scaleTo(const Point & size)
|
|
||||||
{
|
|
||||||
image = image->scaleTo(size, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageIndexed::scaleInteger(int factor)
|
|
||||||
{
|
|
||||||
image = image->scaleInteger(factor, currentPalette, blitMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageRGB::scaleInteger(int factor)
|
|
||||||
{
|
|
||||||
image = image->scaleInteger(factor, nullptr, blitMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageRGB::exportBitmap(const boost::filesystem::path & path) const
|
|
||||||
{
|
|
||||||
image->exportBitmap(path, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLImageBase::isTransparent(const Point & coords) const
|
|
||||||
{
|
|
||||||
return image->isTransparent(coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect SDLImageBase::contentRect() const
|
|
||||||
{
|
|
||||||
return image->contentRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
Point SDLImageBase::dimensions() const
|
|
||||||
{
|
|
||||||
return image->dimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageBase::setAlpha(uint8_t value)
|
|
||||||
{
|
|
||||||
alphaValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageBase::setBlitMode(EImageBlitMode mode)
|
|
||||||
{
|
|
||||||
blitMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLImageRGB::setOverlayColor(const ColorRGBA & color)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SDLImageRGB::playerColored(PlayerColor player)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SDLImageRGB::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SDLImageRGB::adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,9 +35,6 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
|
|||||||
//total size including borders
|
//total size including borders
|
||||||
Point fullSize;
|
Point fullSize;
|
||||||
|
|
||||||
//pre scaled image
|
|
||||||
int preScaleFactor;
|
|
||||||
|
|
||||||
// Keep the original palette, in order to do color switching operation
|
// Keep the original palette, in order to do color switching operation
|
||||||
void savePalette();
|
void savePalette();
|
||||||
|
|
||||||
@ -45,11 +42,11 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
//Load image from def file
|
//Load image from def file
|
||||||
SDLImageShared(const CDefFile *data, size_t frame, size_t group=0, int preScaleFactor=1);
|
SDLImageShared(const CDefFile *data, size_t frame, size_t group=0);
|
||||||
//Load from bitmap file
|
//Load from bitmap file
|
||||||
SDLImageShared(const ImagePath & filename, int preScaleFactor=1);
|
SDLImageShared(const ImagePath & filename);
|
||||||
//Create using existing surface, extraRef will increase refcount on SDL_Surface
|
//Create using existing surface, extraRef will increase refcount on SDL_Surface
|
||||||
SDLImageShared(SDL_Surface * from, int preScaleFactor=1);
|
SDLImageShared(SDL_Surface * from);
|
||||||
~SDLImageShared();
|
~SDLImageShared();
|
||||||
|
|
||||||
void draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const override;
|
void draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const override;
|
||||||
@ -58,7 +55,9 @@ public:
|
|||||||
Point dimensions() const override;
|
Point dimensions() const override;
|
||||||
bool isTransparent(const Point & coords) const override;
|
bool isTransparent(const Point & coords) const override;
|
||||||
Rect contentRect() const override;
|
Rect contentRect() const override;
|
||||||
[[nodiscard]] std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const override;
|
|
||||||
|
const SDL_Palette * getPalette() const override;
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<const ISharedImage> horizontalFlip() const override;
|
[[nodiscard]] std::shared_ptr<const ISharedImage> horizontalFlip() const override;
|
||||||
[[nodiscard]] std::shared_ptr<const ISharedImage> verticalFlip() const override;
|
[[nodiscard]] std::shared_ptr<const ISharedImage> verticalFlip() const override;
|
||||||
[[nodiscard]] std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const override;
|
[[nodiscard]] std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const override;
|
||||||
@ -66,58 +65,3 @@ public:
|
|||||||
|
|
||||||
friend class SDLImageLoader;
|
friend class SDLImageLoader;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDLImageBase : public IImage, boost::noncopyable
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<const ISharedImage> image;
|
|
||||||
|
|
||||||
uint8_t alphaValue;
|
|
||||||
EImageBlitMode blitMode;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SDLImageBase(const std::shared_ptr<const ISharedImage> & image, EImageBlitMode mode);
|
|
||||||
|
|
||||||
bool isTransparent(const Point & coords) const override;
|
|
||||||
Rect contentRect() const override;
|
|
||||||
Point dimensions() const override;
|
|
||||||
void setAlpha(uint8_t value) override;
|
|
||||||
void setBlitMode(EImageBlitMode mode) override;
|
|
||||||
std::shared_ptr<const ISharedImage> getSharedImage() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SDLImageIndexed final : public SDLImageBase
|
|
||||||
{
|
|
||||||
SDL_Palette * currentPalette = nullptr;
|
|
||||||
SDL_Palette * originalPalette = nullptr;
|
|
||||||
|
|
||||||
void setShadowTransparency(float factor);
|
|
||||||
void preparePalette();
|
|
||||||
public:
|
|
||||||
SDLImageIndexed(const std::shared_ptr<const ISharedImage> & image, SDL_Palette * palette, EImageBlitMode mode);
|
|
||||||
~SDLImageIndexed();
|
|
||||||
|
|
||||||
void draw(SDL_Surface * where, const Point & pos, const Rect * src) const override;
|
|
||||||
void setOverlayColor(const ColorRGBA & color) override;
|
|
||||||
void playerColored(PlayerColor player) override;
|
|
||||||
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override;
|
|
||||||
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;
|
|
||||||
void scaleInteger(int factor) override;
|
|
||||||
void scaleTo(const Point & size) override;
|
|
||||||
void exportBitmap(const boost::filesystem::path & path) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SDLImageRGB final : public SDLImageBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using SDLImageBase::SDLImageBase;
|
|
||||||
|
|
||||||
void draw(SDL_Surface * where, const Point & pos, const Rect * src) const override;
|
|
||||||
void setOverlayColor(const ColorRGBA & color) override;
|
|
||||||
void playerColored(PlayerColor player) override;
|
|
||||||
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override;
|
|
||||||
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;
|
|
||||||
void scaleInteger(int factor) override;
|
|
||||||
void scaleTo(const Point & size) override;
|
|
||||||
void exportBitmap(const boost::filesystem::path & path) const override;
|
|
||||||
};
|
|
||||||
|
489
client/renderSDL/ScalableImage.cpp
Normal file
489
client/renderSDL/ScalableImage.cpp
Normal file
@ -0,0 +1,489 @@
|
|||||||
|
/*
|
||||||
|
* ScalableImage.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "StdInc.h"
|
||||||
|
#include "ScalableImage.h"
|
||||||
|
|
||||||
|
#include "SDLImage.h"
|
||||||
|
#include "SDL_Extensions.h"
|
||||||
|
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
|
||||||
|
#include "../render/ColorFilter.h"
|
||||||
|
#include "../render/Colors.h"
|
||||||
|
#include "../render/Graphics.h"
|
||||||
|
#include "../render/IRenderHandler.h"
|
||||||
|
#include "../render/IScreenHandler.h"
|
||||||
|
|
||||||
|
#include "../../lib/constants/EntityIdentifiers.h"
|
||||||
|
|
||||||
|
#include <SDL_surface.h>
|
||||||
|
|
||||||
|
//First 8 colors in def palette used for transparency
|
||||||
|
static constexpr std::array<SDL_Color, 8> sourcePalette = {{
|
||||||
|
{0, 255, 255, SDL_ALPHA_OPAQUE},
|
||||||
|
{255, 150, 255, SDL_ALPHA_OPAQUE},
|
||||||
|
{255, 100, 255, SDL_ALPHA_OPAQUE},
|
||||||
|
{255, 50, 255, SDL_ALPHA_OPAQUE},
|
||||||
|
{255, 0, 255, SDL_ALPHA_OPAQUE},
|
||||||
|
{255, 255, 0, SDL_ALPHA_OPAQUE},
|
||||||
|
{180, 0, 255, SDL_ALPHA_OPAQUE},
|
||||||
|
{0, 255, 0, SDL_ALPHA_OPAQUE}
|
||||||
|
}};
|
||||||
|
|
||||||
|
static constexpr std::array<ColorRGBA, 8> targetPalette = {{
|
||||||
|
{0, 0, 0, 0 }, // 0 - transparency ( used in most images )
|
||||||
|
{0, 0, 0, 64 }, // 1 - shadow border ( used in battle, adventure map def's )
|
||||||
|
{0, 0, 0, 64 }, // 2 - shadow border ( used in fog-of-war def's )
|
||||||
|
{0, 0, 0, 128}, // 3 - shadow body ( used in fog-of-war def's )
|
||||||
|
{0, 0, 0, 128}, // 4 - shadow body ( used in battle, adventure map def's )
|
||||||
|
{0, 0, 0, 0 }, // 5 - selection / owner flag ( used in battle, adventure map def's )
|
||||||
|
{0, 0, 0, 128}, // 6 - shadow body below selection ( used in battle def's )
|
||||||
|
{0, 0, 0, 64 } // 7 - shadow border below selection ( used in battle def's )
|
||||||
|
}};
|
||||||
|
|
||||||
|
static ui8 mixChannels(ui8 c1, ui8 c2, ui8 a1, ui8 a2)
|
||||||
|
{
|
||||||
|
return c1*a1 / 256 + c2*a2*(255 - a1) / 256 / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ColorRGBA addColors(const ColorRGBA & base, const ColorRGBA & over)
|
||||||
|
{
|
||||||
|
return ColorRGBA(
|
||||||
|
mixChannels(over.r, base.r, over.a, base.a),
|
||||||
|
mixChannels(over.g, base.g, over.a, base.a),
|
||||||
|
mixChannels(over.b, base.b, over.a, base.a),
|
||||||
|
static_cast<ui8>(over.a + base.a * (255 - over.a) / 256)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
static bool colorsSimilar (const SDL_Color & lhs, const SDL_Color & rhs)
|
||||||
|
{
|
||||||
|
// it seems that H3 does not requires exact match to replace colors -> (255, 103, 255) gets interpreted as shadow
|
||||||
|
// exact logic is not clear and requires extensive testing with image editing
|
||||||
|
// potential reason is that H3 uses 16-bit color format (565 RGB bits), meaning that 3 least significant bits are lost in red and blue component
|
||||||
|
static const int threshold = 8;
|
||||||
|
|
||||||
|
int diffR = static_cast<int>(lhs.r) - rhs.r;
|
||||||
|
int diffG = static_cast<int>(lhs.g) - rhs.g;
|
||||||
|
int diffB = static_cast<int>(lhs.b) - rhs.b;
|
||||||
|
int diffA = static_cast<int>(lhs.a) - rhs.a;
|
||||||
|
|
||||||
|
return std::abs(diffR) < threshold && std::abs(diffG) < threshold && std::abs(diffB) < threshold && std::abs(diffA) < threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalableImageParameters::ScalableImageParameters(const SDL_Palette * originalPalette, EImageBlitMode blitMode)
|
||||||
|
{
|
||||||
|
if (originalPalette)
|
||||||
|
{
|
||||||
|
palette = SDL_AllocPalette(originalPalette->ncolors);
|
||||||
|
SDL_SetPaletteColors(palette, originalPalette->colors, 0, originalPalette->ncolors);
|
||||||
|
preparePalette(originalPalette, blitMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalableImageParameters::~ScalableImageParameters()
|
||||||
|
{
|
||||||
|
SDL_FreePalette(palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageParameters::preparePalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode)
|
||||||
|
{
|
||||||
|
switch(blitMode)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::ONLY_SHADOW:
|
||||||
|
case EImageBlitMode::ONLY_OVERLAY:
|
||||||
|
adjustPalette(originalPalette, blitMode, ColorFilter::genAlphaShifter(0), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(blitMode)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::SIMPLE:
|
||||||
|
case EImageBlitMode::WITH_SHADOW:
|
||||||
|
case EImageBlitMode::ONLY_SHADOW:
|
||||||
|
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
||||||
|
setShadowTransparency(originalPalette, 1.0);
|
||||||
|
break;
|
||||||
|
case EImageBlitMode::ONLY_BODY:
|
||||||
|
case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
|
||||||
|
case EImageBlitMode::ONLY_OVERLAY:
|
||||||
|
setShadowTransparency(originalPalette, 0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(blitMode)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::ONLY_OVERLAY:
|
||||||
|
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
||||||
|
setOverlayColor(originalPalette, Colors::WHITE_TRUE);
|
||||||
|
break;
|
||||||
|
case EImageBlitMode::ONLY_SHADOW:
|
||||||
|
case EImageBlitMode::ONLY_BODY:
|
||||||
|
setOverlayColor(originalPalette, Colors::TRANSPARENCY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageParameters::setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color)
|
||||||
|
{
|
||||||
|
palette->colors[5] = CSDL_Ext::toSDL(addColors(targetPalette[5], color));
|
||||||
|
|
||||||
|
for (int i : {6,7})
|
||||||
|
{
|
||||||
|
if (colorsSimilar(originalPalette->colors[i], sourcePalette[i]))
|
||||||
|
palette->colors[i] = CSDL_Ext::toSDL(addColors(targetPalette[i], color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageParameters::shiftPalette(const SDL_Palette * originalPalette, uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
|
||||||
|
{
|
||||||
|
std::vector<SDL_Color> shifterColors(colorsToMove);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<colorsToMove; ++i)
|
||||||
|
shifterColors[(i+distanceToMove)%colorsToMove] = originalPalette->colors[firstColorID + i];
|
||||||
|
|
||||||
|
SDL_SetPaletteColors(palette, shifterColors.data(), firstColorID, colorsToMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageParameters::setShadowTransparency(const SDL_Palette * originalPalette, float factor)
|
||||||
|
{
|
||||||
|
ColorRGBA shadow50(0, 0, 0, 128 * factor);
|
||||||
|
ColorRGBA shadow25(0, 0, 0, 64 * factor);
|
||||||
|
|
||||||
|
std::array<SDL_Color, 5> colorsSDL = {
|
||||||
|
originalPalette->colors[0],
|
||||||
|
originalPalette->colors[1],
|
||||||
|
originalPalette->colors[2],
|
||||||
|
originalPalette->colors[3],
|
||||||
|
originalPalette->colors[4]
|
||||||
|
};
|
||||||
|
|
||||||
|
// seems to be used unconditionally
|
||||||
|
colorsSDL[0] = CSDL_Ext::toSDL(Colors::TRANSPARENCY);
|
||||||
|
colorsSDL[1] = CSDL_Ext::toSDL(shadow25);
|
||||||
|
colorsSDL[4] = CSDL_Ext::toSDL(shadow50);
|
||||||
|
|
||||||
|
// seems to be used only if color matches
|
||||||
|
if (colorsSimilar(originalPalette->colors[2], sourcePalette[2]))
|
||||||
|
colorsSDL[2] = CSDL_Ext::toSDL(shadow25);
|
||||||
|
|
||||||
|
if (colorsSimilar(originalPalette->colors[3], sourcePalette[3]))
|
||||||
|
colorsSDL[3] = CSDL_Ext::toSDL(shadow50);
|
||||||
|
|
||||||
|
SDL_SetPaletteColors(palette, colorsSDL.data(), 0, colorsSDL.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageParameters::adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask)
|
||||||
|
{
|
||||||
|
// If shadow is enabled, following colors must be skipped unconditionally
|
||||||
|
if (blitMode == EImageBlitMode::WITH_SHADOW || blitMode == EImageBlitMode::WITH_SHADOW_AND_OVERLAY)
|
||||||
|
colorsToSkipMask |= (1 << 0) + (1 << 1) + (1 << 4);
|
||||||
|
|
||||||
|
// Note: here we skip first colors in the palette that are predefined in H3 images
|
||||||
|
for(int i = 0; i < palette->ncolors; i++)
|
||||||
|
{
|
||||||
|
if (i < std::size(sourcePalette) && colorsSimilar(sourcePalette[i], originalPalette->colors[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(i < std::numeric_limits<uint32_t>::digits && ((colorsToSkipMask >> i) & 1) == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
palette->colors[i] = CSDL_Ext::toSDL(shifter.shiftColor(CSDL_Ext::fromSDL(originalPalette->colors[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalableImageShared::ScalableImageShared(const SharedImageLocator & locator, const std::shared_ptr<const ISharedImage> & baseImage)
|
||||||
|
:locator(locator)
|
||||||
|
{
|
||||||
|
base[0] = baseImage;
|
||||||
|
assert(base[0] != nullptr);
|
||||||
|
|
||||||
|
loadScaledImages(GH.screenHandler().getScalingFactor(), PlayerColor::CANNOT_DETERMINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point ScalableImageShared::dimensions() const
|
||||||
|
{
|
||||||
|
return base[0]->dimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageShared::exportBitmap(const boost::filesystem::path & path, const ScalableImageParameters & parameters) const
|
||||||
|
{
|
||||||
|
base[0]->exportBitmap(path, parameters.palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScalableImageShared::isTransparent(const Point & coords) const
|
||||||
|
{
|
||||||
|
return base[0]->isTransparent(coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect ScalableImageShared::contentRect() const
|
||||||
|
{
|
||||||
|
return base[0]->contentRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageShared::draw(SDL_Surface * where, const Point & dest, const Rect * src, const ScalableImageParameters & parameters, int scalingFactor)
|
||||||
|
{
|
||||||
|
const auto & flipAndDraw = [&](FlippedImages & images, const ColorRGBA & colorMultiplier, uint8_t alphaValue){
|
||||||
|
int index = 0;
|
||||||
|
if (parameters.flipVertical)
|
||||||
|
{
|
||||||
|
if (!images[index|1])
|
||||||
|
images[index|1] = images[index]->verticalFlip();
|
||||||
|
|
||||||
|
index |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.flipHorizontal)
|
||||||
|
{
|
||||||
|
if (!images[index|2])
|
||||||
|
images[index|2] = images[index]->horizontalFlip();
|
||||||
|
|
||||||
|
index |= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
images[index]->draw(where, parameters.palette, dest, src, colorMultiplier, alphaValue, locator.layer);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (scalingFactor == 1)
|
||||||
|
{
|
||||||
|
flipAndDraw(base, parameters.colorMultiplier, parameters.alphaValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (scaled.at(scalingFactor).shadow.at(0))
|
||||||
|
flipAndDraw(scaled.at(scalingFactor).shadow, Colors::WHITE_TRUE, parameters.alphaValue);
|
||||||
|
|
||||||
|
if (parameters.player != PlayerColor::CANNOT_DETERMINE)
|
||||||
|
{
|
||||||
|
scaled.at(scalingFactor).playerColored[parameters.player.getNum()]->draw(where, parameters.palette, dest, src, Colors::WHITE_TRUE, parameters.alphaValue, locator.layer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (scaled.at(scalingFactor).body.at(0))
|
||||||
|
flipAndDraw(scaled.at(scalingFactor).body, parameters.colorMultiplier, parameters.alphaValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scaled.at(scalingFactor).overlay.at(0))
|
||||||
|
flipAndDraw(scaled.at(scalingFactor).overlay, parameters.ovelayColorMultiplier, static_cast<int>(parameters.alphaValue) * parameters.ovelayColorMultiplier.a / 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SDL_Palette * ScalableImageShared::getPalette() const
|
||||||
|
{
|
||||||
|
return base[0]->getPalette();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ScalableImageInstance> ScalableImageShared::createImageReference()
|
||||||
|
{
|
||||||
|
return std::make_shared<ScalableImageInstance>(shared_from_this(), locator.layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalableImageInstance::ScalableImageInstance(const std::shared_ptr<ScalableImageShared> & image, EImageBlitMode blitMode)
|
||||||
|
:image(image)
|
||||||
|
,parameters(image->getPalette(), blitMode)
|
||||||
|
,blitMode(blitMode)
|
||||||
|
{
|
||||||
|
assert(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::scaleTo(const Point & size)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::exportBitmap(const boost::filesystem::path & path) const
|
||||||
|
{
|
||||||
|
image->exportBitmap(path, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScalableImageInstance::isTransparent(const Point & coords) const
|
||||||
|
{
|
||||||
|
return image->isTransparent(coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect ScalableImageInstance::contentRect() const
|
||||||
|
{
|
||||||
|
return image->contentRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Point ScalableImageInstance::dimensions() const
|
||||||
|
{
|
||||||
|
return image->dimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::setAlpha(uint8_t value)
|
||||||
|
{
|
||||||
|
parameters.alphaValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const
|
||||||
|
{
|
||||||
|
image->draw(where, pos, src, parameters, scalingFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::setOverlayColor(const ColorRGBA & color)
|
||||||
|
{
|
||||||
|
parameters.ovelayColorMultiplier = color;
|
||||||
|
|
||||||
|
if (parameters.palette)
|
||||||
|
parameters.setOverlayColor(image->getPalette(), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::playerColored(PlayerColor player)
|
||||||
|
{
|
||||||
|
parameters.player = player;
|
||||||
|
|
||||||
|
if (!parameters.palette)
|
||||||
|
parameters.playerColored(player);
|
||||||
|
|
||||||
|
image->preparePlayerColoredImage(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageParameters::playerColored(PlayerColor player)
|
||||||
|
{
|
||||||
|
graphics->setPlayerPalette(palette, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
|
||||||
|
{
|
||||||
|
if (parameters.palette)
|
||||||
|
parameters.shiftPalette(image->getPalette(),firstColorID, colorsToMove, distanceToMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask)
|
||||||
|
{
|
||||||
|
if (parameters.palette)
|
||||||
|
parameters.adjustPalette(image->getPalette(), blitMode, shifter, colorsToSkipMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::horizontalFlip()
|
||||||
|
{
|
||||||
|
parameters.flipHorizontal = !parameters.flipHorizontal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageInstance::verticalFlip()
|
||||||
|
{
|
||||||
|
parameters.flipVertical = !parameters.flipVertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const ISharedImage> ScalableImageShared::loadOrGenerateImage(EImageBlitMode mode, int8_t scalingFactor, PlayerColor color) const
|
||||||
|
{
|
||||||
|
ImageLocator loadingLocator;
|
||||||
|
|
||||||
|
loadingLocator.image = locator.image;
|
||||||
|
loadingLocator.defFile = locator.defFile;
|
||||||
|
loadingLocator.defFrame = locator.defFrame;
|
||||||
|
loadingLocator.defGroup = locator.defGroup;
|
||||||
|
loadingLocator.layer = mode;
|
||||||
|
loadingLocator.scalingFactor = scalingFactor;
|
||||||
|
loadingLocator.playerColored = color;
|
||||||
|
|
||||||
|
// best case - requested image is already available in filesystem
|
||||||
|
auto loadedImage = GH.renderHandler().loadSingleImage(loadingLocator);
|
||||||
|
if (loadedImage)
|
||||||
|
return loadedImage;
|
||||||
|
|
||||||
|
// alternatively, find largest pre-scaled image, load it and rescale to desired scaling
|
||||||
|
Point targetSize = base[0]->dimensions() * scalingFactor;
|
||||||
|
for (int8_t scaling = 4; scaling > 1; --scaling)
|
||||||
|
{
|
||||||
|
loadingLocator.scalingFactor = scaling;
|
||||||
|
auto loadedImage = GH.renderHandler().loadSingleImage(loadingLocator);
|
||||||
|
if (loadedImage)
|
||||||
|
return loadedImage->scaleTo(targetSize, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if all else fails - use base (presumably, indexed) image and convert it to desired form
|
||||||
|
ScalableImageParameters parameters(getPalette(), mode);
|
||||||
|
if (color != PlayerColor::CANNOT_DETERMINE)
|
||||||
|
parameters.playerColored(color);
|
||||||
|
return base[0]->scaleInteger(scalingFactor, parameters.palette, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageShared::loadScaledImages(int8_t scalingFactor, PlayerColor color)
|
||||||
|
{
|
||||||
|
if (scalingFactor == 1)
|
||||||
|
return; // no op. TODO: consider loading 1x images for mods, as alternative to palette-based animations
|
||||||
|
|
||||||
|
if (scaled[scalingFactor].body[0] == nullptr)
|
||||||
|
{
|
||||||
|
switch(locator.layer)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::OPAQUE:
|
||||||
|
case EImageBlitMode::COLORKEY:
|
||||||
|
case EImageBlitMode::SIMPLE:
|
||||||
|
scaled[scalingFactor].body[0] = loadOrGenerateImage(locator.layer, scalingFactor, PlayerColor::CANNOT_DETERMINE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
||||||
|
case EImageBlitMode::ONLY_BODY:
|
||||||
|
scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY, scalingFactor, PlayerColor::CANNOT_DETERMINE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EImageBlitMode::WITH_SHADOW:
|
||||||
|
case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
|
||||||
|
scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY, scalingFactor, PlayerColor::CANNOT_DETERMINE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color != PlayerColor::CANNOT_DETERMINE && scaled[scalingFactor].playerColored[color.getNum()] == nullptr)
|
||||||
|
{
|
||||||
|
switch(locator.layer)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::OPAQUE:
|
||||||
|
case EImageBlitMode::COLORKEY:
|
||||||
|
case EImageBlitMode::SIMPLE:
|
||||||
|
scaled[scalingFactor].playerColored[color.getNum()] = loadOrGenerateImage(locator.layer, scalingFactor, color);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
||||||
|
case EImageBlitMode::ONLY_BODY:
|
||||||
|
scaled[scalingFactor].playerColored[color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY, scalingFactor, color);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EImageBlitMode::WITH_SHADOW:
|
||||||
|
case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
|
||||||
|
scaled[scalingFactor].playerColored[color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY, scalingFactor, color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scaled[scalingFactor].shadow[0] == nullptr)
|
||||||
|
{
|
||||||
|
switch(locator.layer)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::WITH_SHADOW:
|
||||||
|
case EImageBlitMode::ONLY_SHADOW:
|
||||||
|
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
||||||
|
scaled[scalingFactor].shadow[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SHADOW, scalingFactor, PlayerColor::CANNOT_DETERMINE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scaled[scalingFactor].overlay[0] == nullptr)
|
||||||
|
{
|
||||||
|
switch(locator.layer)
|
||||||
|
{
|
||||||
|
case EImageBlitMode::ONLY_OVERLAY:
|
||||||
|
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY:
|
||||||
|
scaled[scalingFactor].overlay[0] = loadOrGenerateImage(EImageBlitMode::ONLY_OVERLAY, scalingFactor, PlayerColor::CANNOT_DETERMINE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalableImageShared::preparePlayerColoredImage(PlayerColor color)
|
||||||
|
{
|
||||||
|
loadScaledImages(GH.screenHandler().getScalingFactor(), color);
|
||||||
|
}
|
124
client/renderSDL/ScalableImage.h
Normal file
124
client/renderSDL/ScalableImage.h
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* ScalableImage.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../render/IImage.h"
|
||||||
|
#include "../render/ImageLocator.h"
|
||||||
|
#include "../render/Colors.h"
|
||||||
|
|
||||||
|
#include "../../lib/Color.h"
|
||||||
|
|
||||||
|
struct SDL_Palette;
|
||||||
|
|
||||||
|
class ScalableImageInstance;
|
||||||
|
|
||||||
|
struct ScalableImageParameters : boost::noncopyable
|
||||||
|
{
|
||||||
|
SDL_Palette * palette = nullptr;
|
||||||
|
|
||||||
|
ColorRGBA colorMultiplier = Colors::WHITE_TRUE;
|
||||||
|
ColorRGBA ovelayColorMultiplier = Colors::WHITE_TRUE;
|
||||||
|
|
||||||
|
PlayerColor player = PlayerColor::CANNOT_DETERMINE;
|
||||||
|
uint8_t alphaValue = 255;
|
||||||
|
|
||||||
|
bool flipVertical = false;
|
||||||
|
bool flipHorizontal = false;
|
||||||
|
|
||||||
|
ScalableImageParameters(const SDL_Palette * originalPalette, EImageBlitMode blitMode);
|
||||||
|
~ScalableImageParameters();
|
||||||
|
|
||||||
|
void setShadowTransparency(const SDL_Palette * originalPalette, float factor);
|
||||||
|
void shiftPalette(const SDL_Palette * originalPalette, uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove);
|
||||||
|
void playerColored(PlayerColor player);
|
||||||
|
void setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color);
|
||||||
|
void preparePalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode);
|
||||||
|
void adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScalableImageShared final : public std::enable_shared_from_this<ScalableImageShared>, boost::noncopyable
|
||||||
|
{
|
||||||
|
static constexpr int maxScaling = 4;
|
||||||
|
static constexpr int maxFlips = 4;
|
||||||
|
|
||||||
|
using FlippedImages = std::array<std::shared_ptr<const ISharedImage>, maxFlips>;
|
||||||
|
using PlayerColoredImages = std::array<std::shared_ptr<const ISharedImage>, PlayerColor::PLAYER_LIMIT_I>;
|
||||||
|
|
||||||
|
struct ScaledImage
|
||||||
|
{
|
||||||
|
/// Upscaled shadow of our image, may be null
|
||||||
|
FlippedImages shadow;
|
||||||
|
|
||||||
|
/// Upscaled main part of our image, may be null
|
||||||
|
FlippedImages body;
|
||||||
|
|
||||||
|
/// Upscaled overlay (player color, selection highlight) of our image, may be null
|
||||||
|
FlippedImages overlay;
|
||||||
|
|
||||||
|
// player-colored images of this particular scale. These are never flipped in h3
|
||||||
|
PlayerColoredImages playerColored;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1x image, usually indexed. Array of 4 images for every potential flip
|
||||||
|
FlippedImages base;
|
||||||
|
|
||||||
|
// 1x-4x images. 1x versions are only used if dedicated image is present, othervice palette transform is applied to base image
|
||||||
|
std::array<ScaledImage, maxScaling> scaled;
|
||||||
|
|
||||||
|
const SharedImageLocator locator;
|
||||||
|
|
||||||
|
std::shared_ptr<const ISharedImage> loadOrGenerateImage(EImageBlitMode mode, int8_t scalingFactor, PlayerColor color) const;
|
||||||
|
|
||||||
|
void loadScaledImages(int8_t scalingFactor, PlayerColor color);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScalableImageShared(const SharedImageLocator & locator, const std::shared_ptr<const ISharedImage> & baseImage);
|
||||||
|
|
||||||
|
Point dimensions() const;
|
||||||
|
void exportBitmap(const boost::filesystem::path & path, const ScalableImageParameters & parameters) const;
|
||||||
|
bool isTransparent(const Point & coords) const;
|
||||||
|
Rect contentRect() const;
|
||||||
|
void draw(SDL_Surface * where, const Point & dest, const Rect * src, const ScalableImageParameters & parameters, int scalingFactor);
|
||||||
|
|
||||||
|
const SDL_Palette * getPalette() const;
|
||||||
|
|
||||||
|
std::shared_ptr<ScalableImageInstance> createImageReference();
|
||||||
|
|
||||||
|
void preparePlayerColoredImage(PlayerColor color);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScalableImageInstance final : public IImage
|
||||||
|
{
|
||||||
|
friend class ScalableImageShared;
|
||||||
|
|
||||||
|
std::shared_ptr<ScalableImageShared> image;
|
||||||
|
|
||||||
|
ScalableImageParameters parameters;
|
||||||
|
EImageBlitMode blitMode;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScalableImageInstance(const std::shared_ptr<ScalableImageShared> & image, EImageBlitMode blitMode);
|
||||||
|
|
||||||
|
void scaleTo(const Point & size) override;
|
||||||
|
void exportBitmap(const boost::filesystem::path & path) const override;
|
||||||
|
bool isTransparent(const Point & coords) const override;
|
||||||
|
Rect contentRect() const override;
|
||||||
|
Point dimensions() const override;
|
||||||
|
void setAlpha(uint8_t value) override;
|
||||||
|
void draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const override;
|
||||||
|
void setOverlayColor(const ColorRGBA & color) override;
|
||||||
|
void playerColored(PlayerColor player) override;
|
||||||
|
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override;
|
||||||
|
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;
|
||||||
|
|
||||||
|
void horizontalFlip();
|
||||||
|
void verticalFlip();
|
||||||
|
};
|
||||||
|
|
@ -53,8 +53,8 @@ CPicture::CPicture( const ImagePath & bmpname )
|
|||||||
: CPicture(bmpname, Point(0,0))
|
: CPicture(bmpname, Point(0,0))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CPicture::CPicture( const ImagePath & bmpname, const Point & position )
|
CPicture::CPicture( const ImagePath & bmpname, const Point & position, EImageBlitMode mode )
|
||||||
: bg(GH.renderHandler().loadImage(bmpname, EImageBlitMode::COLORKEY))
|
: bg(GH.renderHandler().loadImage(bmpname, mode))
|
||||||
, needRefresh(false)
|
, needRefresh(false)
|
||||||
{
|
{
|
||||||
pos.x += position.x;
|
pos.x += position.x;
|
||||||
@ -74,6 +74,10 @@ CPicture::CPicture( const ImagePath & bmpname, const Point & position )
|
|||||||
addUsedEvents(SHOW_POPUP);
|
addUsedEvents(SHOW_POPUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPicture::CPicture( const ImagePath & bmpname, const Point & position )
|
||||||
|
:CPicture(bmpname, position, EImageBlitMode::COLORKEY)
|
||||||
|
{}
|
||||||
|
|
||||||
CPicture::CPicture(const ImagePath & bmpname, const Rect &SrcRect, int x, int y)
|
CPicture::CPicture(const ImagePath & bmpname, const Rect &SrcRect, int x, int y)
|
||||||
: CPicture(bmpname, Point(x,y))
|
: CPicture(bmpname, Point(x,y))
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@ class CAnimImage;
|
|||||||
class CLabel;
|
class CLabel;
|
||||||
class CAnimation;
|
class CAnimation;
|
||||||
class IImage;
|
class IImage;
|
||||||
|
enum class EImageBlitMode : uint8_t;
|
||||||
|
|
||||||
// Image class
|
// Image class
|
||||||
class CPicture : public CIntObject
|
class CPicture : public CIntObject
|
||||||
@ -49,6 +50,7 @@ public:
|
|||||||
|
|
||||||
/// Loads image from specified file name
|
/// Loads image from specified file name
|
||||||
CPicture(const ImagePath & bmpname);
|
CPicture(const ImagePath & bmpname);
|
||||||
|
CPicture(const ImagePath & bmpname, const Point & position, EImageBlitMode mode);
|
||||||
CPicture(const ImagePath & bmpname, const Point & position);
|
CPicture(const ImagePath & bmpname, const Point & position);
|
||||||
CPicture(const ImagePath & bmpname, int x, int y);
|
CPicture(const ImagePath & bmpname, int x, int y);
|
||||||
|
|
||||||
|
@ -570,9 +570,8 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
|
|
||||||
background = std::make_shared<CPicture>(town->getTown()->clientInfo.townBackground);
|
background = std::make_shared<CPicture>(town->getTown()->clientInfo.townBackground, Point(0,0), EImageBlitMode::OPAQUE);
|
||||||
background->needRefresh = true;
|
background->needRefresh = true;
|
||||||
background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
|
|
||||||
pos.w = background->pos.w;
|
pos.w = background->pos.w;
|
||||||
pos.h = background->pos.h;
|
pos.h = background->pos.h;
|
||||||
|
|
||||||
|
@ -139,9 +139,8 @@ std::shared_ptr<CPicture> CMapOverviewWidget::buildDrawMinimap(const JsonNode &
|
|||||||
double resize = maxSideLengthSrc / maxSideLengthDst;
|
double resize = maxSideLengthSrc / maxSideLengthDst;
|
||||||
Point newMinimapSize = Point(minimapRect.w / resize, minimapRect.h / resize);
|
Point newMinimapSize = Point(minimapRect.w / resize, minimapRect.h / resize);
|
||||||
|
|
||||||
Canvas canvasScaled = Canvas(Point(rect.w, rect.h), CanvasScalingPolicy::AUTO);
|
std::shared_ptr<IImage> img = GH.renderHandler().createImage(minimaps[id].getInternalSurface());
|
||||||
canvasScaled.drawScaled(minimaps[id], Point((rect.w - newMinimapSize.x) / 2, (rect.h - newMinimapSize.y) / 2), newMinimapSize);
|
img->scaleTo(newMinimapSize);
|
||||||
std::shared_ptr<IImage> img = GH.renderHandler().createImage(canvasScaled.getInternalSurface());
|
|
||||||
|
|
||||||
return std::make_shared<CPicture>(img, Point(rect.x, rect.y));
|
return std::make_shared<CPicture>(img, Point(rect.x, rect.y));
|
||||||
}
|
}
|
||||||
|
@ -87,8 +87,7 @@ std::shared_ptr<CPicture> CWindowObject::createBg(const ImagePath & imageName, b
|
|||||||
if(imageName.empty())
|
if(imageName.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto image = std::make_shared<CPicture>(imageName);
|
auto image = std::make_shared<CPicture>(imageName, Point(0,0), EImageBlitMode::OPAQUE);
|
||||||
image->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
|
|
||||||
if(playerColored)
|
if(playerColored)
|
||||||
image->setPlayerColor(LOCPLINT->playerID);
|
image->setPlayerColor(LOCPLINT->playerID);
|
||||||
return image;
|
return image;
|
||||||
@ -116,8 +115,7 @@ void CWindowObject::updateShadow()
|
|||||||
void CWindowObject::setShadow(bool on)
|
void CWindowObject::setShadow(bool on)
|
||||||
{
|
{
|
||||||
//size of shadow
|
//size of shadow
|
||||||
int sizeOriginal = 8;
|
int size = 8;
|
||||||
int size = sizeOriginal * GH.screenHandler().getScalingFactor();
|
|
||||||
|
|
||||||
if(on == !shadowParts.empty())
|
if(on == !shadowParts.empty())
|
||||||
return;
|
return;
|
||||||
@ -182,9 +180,9 @@ void CWindowObject::setShadow(bool on)
|
|||||||
//FIXME: do something with this points
|
//FIXME: do something with this points
|
||||||
Point shadowStart;
|
Point shadowStart;
|
||||||
if (options & BORDERED)
|
if (options & BORDERED)
|
||||||
shadowStart = Point(sizeOriginal - 14, sizeOriginal - 14);
|
shadowStart = Point(size - 14, size - 14);
|
||||||
else
|
else
|
||||||
shadowStart = Point(sizeOriginal, sizeOriginal);
|
shadowStart = Point(size, size);
|
||||||
|
|
||||||
Point shadowPos;
|
Point shadowPos;
|
||||||
if (options & BORDERED)
|
if (options & BORDERED)
|
||||||
@ -200,8 +198,8 @@ void CWindowObject::setShadow(bool on)
|
|||||||
|
|
||||||
//create base 8x8 piece of shadow
|
//create base 8x8 piece of shadow
|
||||||
SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
|
SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
|
||||||
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, (fullsize.x - sizeOriginal) * GH.screenHandler().getScalingFactor(), size);
|
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, (fullsize.x - size), size);
|
||||||
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, (fullsize.y - sizeOriginal) * GH.screenHandler().getScalingFactor());
|
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, (fullsize.y - size));
|
||||||
|
|
||||||
blitAlphaCol(shadowBottom, 0);
|
blitAlphaCol(shadowBottom, 0);
|
||||||
blitAlphaRow(shadowRight, 0);
|
blitAlphaRow(shadowRight, 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user