mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-25 21:38:59 +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/CursorSoftware.cpp
|
||||
renderSDL/FontChain.cpp
|
||||
renderSDL/ImageScaled.cpp
|
||||
renderSDL/ScalableImage.cpp
|
||||
renderSDL/RenderHandler.cpp
|
||||
renderSDL/SDLImage.cpp
|
||||
renderSDL/SDLImageLoader.cpp
|
||||
@ -307,7 +307,7 @@ set(vcmiclientcommon_HEADERS
|
||||
renderSDL/CursorHardware.h
|
||||
renderSDL/CursorSoftware.h
|
||||
renderSDL/FontChain.h
|
||||
renderSDL/ImageScaled.h
|
||||
renderSDL/ScalableImage.h
|
||||
renderSDL/RenderHandler.h
|
||||
renderSDL/SDLImage.h
|
||||
renderSDL/SDLImageLoader.h
|
||||
|
@ -58,10 +58,9 @@ void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"));
|
||||
locator.scalingFactor = 1;
|
||||
auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"), EImageBlitMode::OPAQUE);
|
||||
|
||||
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.draw(img, Point(0, 0), Rect(0, 0, 575, 585));
|
||||
@ -88,10 +87,9 @@ void AssetGenerator::createBigSpellBook()
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("SpelBack"));
|
||||
locator.scalingFactor = 1;
|
||||
auto locator = ImageLocator(ImagePath::builtin("SpelBack"), EImageBlitMode::OPAQUE);
|
||||
|
||||
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);
|
||||
// edges
|
||||
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);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"));
|
||||
locator.scalingFactor = 1;
|
||||
auto locator = ImageLocator(ImagePath::builtin("DiBoxBck"), EImageBlitMode::OPAQUE);
|
||||
|
||||
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
|
||||
auto filterSettings = VLC->settingsHandler->getFullConfig()["interface"]["playerColoredBackground"];
|
||||
@ -199,10 +196,10 @@ void AssetGenerator::createCombatUnitNumberWindow()
|
||||
!CResourceHandler::get("local")->createResource(savePathNegative.getOriginalName() + ".png"))
|
||||
return;
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"));
|
||||
locator.scalingFactor = 1;
|
||||
auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"), EImageBlitMode::OPAQUE);
|
||||
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 shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );
|
||||
@ -233,10 +230,9 @@ void AssetGenerator::createCampaignBackground()
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"));
|
||||
locator.scalingFactor = 1;
|
||||
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
|
||||
|
||||
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.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));
|
||||
|
||||
// skull
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"));
|
||||
locatorSkull.scalingFactor = 1;
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull, EImageBlitMode::OPAQUE);
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"), EImageBlitMode::OPAQUE);
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
|
||||
|
||||
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
|
||||
@ -290,10 +285,9 @@ void AssetGenerator::createChroniclesCampaignImages()
|
||||
continue;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
|
||||
auto locator = ImageLocator(imgPathBg);
|
||||
locator.scalingFactor = 1;
|
||||
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
|
||||
|
||||
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);
|
||||
|
||||
switch (i)
|
||||
@ -323,9 +317,8 @@ void AssetGenerator::createChroniclesCampaignImages()
|
||||
canvas.draw(img, Point(0, 0), Rect(268, 210, 200, 116));
|
||||
|
||||
//skull
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"));
|
||||
locatorSkull.scalingFactor = 1;
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull, EImageBlitMode::OPAQUE);
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"), EImageBlitMode::OPAQUE);
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
canvas.draw(imgSkull, Point(162, 94), Rect(162, 94, 41, 22));
|
||||
canvas.draw(img, Point(162, 94), Rect(424, 304, 14, 4));
|
||||
canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
|
||||
@ -403,8 +396,7 @@ void AssetGenerator::createPaletteShiftedSprites()
|
||||
return;
|
||||
|
||||
auto imgLoc = anim->getImageLocator(j, 0);
|
||||
imgLoc.scalingFactor = 1;
|
||||
auto img = GH.renderHandler().loadImage(imgLoc, EImageBlitMode::COLORKEY);
|
||||
auto img = GH.renderHandler().loadImage(imgLoc);
|
||||
for(int k = 0; k < paletteAnimations[i].size(); 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))
|
||||
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)
|
||||
{
|
||||
@ -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() );
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
@ -114,7 +114,7 @@ void Canvas::draw(const std::shared_ptr<IImage>& image, const Point & pos, const
|
||||
Rect realSourceRect = sourceRect * getScalingFactor();
|
||||
assert(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)
|
||||
@ -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 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;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public:
|
||||
int getScalingFactor() const;
|
||||
|
||||
/// Compatibility method. AVOID USAGE. To be removed once SDL abstraction layer is finished.
|
||||
SDL_Surface * getInternalSurface();
|
||||
SDL_Surface * getInternalSurface() const;
|
||||
|
||||
/// get the render area
|
||||
Rect getRenderArea() const;
|
||||
|
@ -68,10 +68,9 @@ class IImage
|
||||
{
|
||||
public:
|
||||
//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 scaleInteger(int factor) = 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 setAlpha(uint8_t value) = 0;
|
||||
virtual void setBlitMode(EImageBlitMode mode) = 0;
|
||||
|
||||
//only indexed bitmaps with 7 special colors
|
||||
virtual void setOverlayColor(const ColorRGBA & color) = 0;
|
||||
|
||||
virtual std::shared_ptr<const ISharedImage> getSharedImage() const = 0;
|
||||
|
||||
virtual ~IImage() = default;
|
||||
};
|
||||
|
||||
@ -114,13 +110,13 @@ public:
|
||||
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;
|
||||
|
||||
[[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> 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> scaleTo(const Point & size, SDL_Palette * palette) const = 0;
|
||||
|
||||
|
||||
virtual ~ISharedImage() = default;
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ struct SDL_Surface;
|
||||
class IFont;
|
||||
class IImage;
|
||||
class CAnimation;
|
||||
class SDLImageShared;
|
||||
enum class EImageBlitMode : uint8_t;
|
||||
enum EFonts : int8_t;
|
||||
|
||||
@ -32,10 +33,13 @@ public:
|
||||
virtual void onLibraryLoadingFinished(const Services * services) = 0;
|
||||
|
||||
/// 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 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
|
||||
/// Surface will be shared, caller must still free it with SDL_FreeSurface
|
||||
virtual std::shared_ptr<IImage> createImage(SDL_Surface * source) = 0;
|
||||
|
@ -15,11 +15,10 @@
|
||||
|
||||
#include "../../lib/json/JsonNode.h"
|
||||
|
||||
ImageLocator::ImageLocator(const JsonNode & config)
|
||||
SharedImageLocator::SharedImageLocator(const JsonNode & config, EImageBlitMode mode)
|
||||
: defFrame(config["defFrame"].Integer())
|
||||
, defGroup(config["defGroup"].Integer())
|
||||
, verticalFlip(config["verticalFlip"].Bool())
|
||||
, horizontalFlip(config["horizontalFlip"].Bool())
|
||||
, layer(mode)
|
||||
{
|
||||
if(!config["file"].isNull())
|
||||
image = ImagePath::fromJson(config["file"]);
|
||||
@ -28,19 +27,28 @@ ImageLocator::ImageLocator(const JsonNode & config)
|
||||
defFile = AnimationPath::fromJson(config["defFile"]);
|
||||
}
|
||||
|
||||
ImageLocator::ImageLocator(const ImagePath & path)
|
||||
SharedImageLocator::SharedImageLocator(const ImagePath & path, EImageBlitMode mode)
|
||||
: 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)
|
||||
, defFrame(frame)
|
||||
, 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)
|
||||
return image < other.image;
|
||||
@ -50,14 +58,6 @@ bool ImageLocator::operator<(const ImageLocator & other) const
|
||||
return defGroup < other.defGroup;
|
||||
if(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)
|
||||
return layer < other.layer;
|
||||
|
||||
@ -68,70 +68,3 @@ bool ImageLocator::empty() const
|
||||
{
|
||||
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/constants/EntityIdentifiers.h"
|
||||
|
||||
struct ImageLocator
|
||||
struct SharedImageLocator
|
||||
{
|
||||
std::optional<ImagePath> image;
|
||||
std::optional<AnimationPath> defFile;
|
||||
int defFrame = -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 horizontalFlip = false;
|
||||
int8_t scalingFactor = 0; // 0 = auto / use default scaling
|
||||
int8_t preScaledFactor = 1;
|
||||
EImageBlitMode layer = EImageBlitMode::OPAQUE;
|
||||
|
||||
ImageLocator() = default;
|
||||
ImageLocator(const AnimationPath & path, int frame, int group);
|
||||
explicit ImageLocator(const JsonNode & config);
|
||||
explicit ImageLocator(const ImagePath & path);
|
||||
using SharedImageLocator::SharedImageLocator;
|
||||
ImageLocator(const JsonNode & config, EImageBlitMode layer);
|
||||
|
||||
bool operator < (const ImageLocator & other) 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));
|
||||
|
||||
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 oldCursor = cursor;
|
||||
|
@ -65,7 +65,7 @@ void CursorSoftware::updateTexture()
|
||||
|
||||
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);
|
||||
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 "SDLImage.h"
|
||||
#include "ImageScaled.h"
|
||||
#include "ScalableImage.h"
|
||||
#include "FontChain.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
@ -22,6 +22,7 @@
|
||||
#include "../render/ColorFilter.h"
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../../lib/json/JsonUtils.h"
|
||||
#include "../../lib/CThreadHelper.h"
|
||||
#include "../../lib/filesystem/Filesystem.h"
|
||||
#include "../../lib/VCMIDirs.h"
|
||||
|
||||
@ -55,60 +56,7 @@ std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath &
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<ResourcePath> RenderHandler::getPathForScaleFactor(const ResourcePath & path, const std::string & factor)
|
||||
{
|
||||
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)
|
||||
void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config, EImageBlitMode mode)
|
||||
{
|
||||
std::string basepath;
|
||||
basepath = config["basepath"].String();
|
||||
@ -128,7 +76,7 @@ void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & c
|
||||
JsonNode toAdd = frame;
|
||||
JsonUtils::inherit(toAdd, base);
|
||||
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"))
|
||||
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);
|
||||
auto animPath = AnimationPath::builtin(tmp.first.getName());
|
||||
AnimationPath actualPath = boost::starts_with(animPath.getName(), "SPRITES") ? animPath : animPath.addPrefix("SPRITES/");
|
||||
static constexpr std::array scaledSpritesPath = {
|
||||
"", // 0x
|
||||
"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);
|
||||
|
||||
@ -184,15 +143,11 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
|
||||
std::unique_ptr<ui8[]> textData(new ui8[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;
|
||||
return animationLayouts[actualPath];
|
||||
}
|
||||
@ -202,209 +157,170 @@ int RenderHandler::getScalingFactor() const
|
||||
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))
|
||||
return ImageLocator(ImagePath::builtin("DEFAULT"));
|
||||
return ImageLocator(ImagePath::builtin("DEFAULT"), mode);
|
||||
|
||||
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);
|
||||
if (locator.image || locator.defFile)
|
||||
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);
|
||||
if (it != imageFiles.end())
|
||||
return it->second;
|
||||
|
||||
// TODO: order should be different:
|
||||
// 1) try to find correctly scaled image
|
||||
// 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);
|
||||
auto sdlImage = loadImageFromFileUncached(locator);
|
||||
auto scaledImage = std::make_shared<ScalableImageShared>(locator, sdlImage);
|
||||
|
||||
storeCachedImage(locator, 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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))
|
||||
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup, preScaledFactor);
|
||||
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup);
|
||||
else
|
||||
{
|
||||
logGlobal->error("Frame %d in group %d not found in file: %s",
|
||||
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!");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#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))
|
||||
return imageFiles.at(locator);
|
||||
assert(locator.scalingFactor != 0);
|
||||
|
||||
auto result = loadImageFromFileUncached(locator);
|
||||
storeCachedImage(locator, result);
|
||||
return result;
|
||||
static constexpr std::array scaledDataPath = {
|
||||
"", // 0x
|
||||
"DATA/",
|
||||
"DATA2X/",
|
||||
"DATA3X/",
|
||||
"DATA4X/",
|
||||
};
|
||||
|
||||
static constexpr std::array scaledSpritesPath = {
|
||||
"", // 0x
|
||||
"SPRITES/",
|
||||
"SPRITES2X/",
|
||||
"SPRITES3X/",
|
||||
"SPRITES4X/",
|
||||
};
|
||||
|
||||
if(locator.image)
|
||||
{
|
||||
std::string imagePathString = locator.image->getName();
|
||||
|
||||
if(locator.layer == EImageBlitMode::ONLY_OVERLAY)
|
||||
imagePathString += "-OVERLAY";
|
||||
if(locator.layer == EImageBlitMode::ONLY_SHADOW)
|
||||
imagePathString += "-SHADOW";
|
||||
|
||||
auto imagePath = ImagePath::builtin(imagePathString);
|
||||
auto imagePathSprites = ImagePath::builtin(imagePathString).addPrefix(scaledSpritesPath.at(locator.scalingFactor));
|
||||
auto imagePathData = ImagePath::builtin(imagePathString).addPrefix(scaledDataPath.at(locator.scalingFactor));
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePathSprites))
|
||||
return std::make_shared<SDLImageShared>(imagePathSprites);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePathData))
|
||||
return std::make_shared<SDLImageShared>(imagePathData);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePath))
|
||||
return std::make_shared<SDLImageShared>(imagePath);
|
||||
}
|
||||
|
||||
if(locator.defFile)
|
||||
{
|
||||
AnimationPath defFilePath = locator.defFile->addPrefix(scaledSpritesPath.at(locator.scalingFactor));
|
||||
auto defFile = getAnimationFile(defFilePath);
|
||||
|
||||
if(defFile && defFile->hasFrame(locator.defFrame, locator.defGroup))
|
||||
{
|
||||
return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const ISharedImage> RenderHandler::transformImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image)
|
||||
{
|
||||
if (imageFiles.count(locator))
|
||||
return imageFiles.at(locator);
|
||||
|
||||
auto result = image;
|
||||
|
||||
if (locator.verticalFlip)
|
||||
result = result->verticalFlip();
|
||||
|
||||
if (locator.horizontalFlip)
|
||||
result = result->horizontalFlip();
|
||||
|
||||
storeCachedImage(locator, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<const ISharedImage> RenderHandler::scaleImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image)
|
||||
{
|
||||
if (imageFiles.count(locator))
|
||||
return imageFiles.at(locator);
|
||||
|
||||
auto handle = image->createImageReference(locator.layer);
|
||||
|
||||
assert(locator.scalingFactor != 1); // should be filtered-out before
|
||||
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)
|
||||
std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator)
|
||||
{
|
||||
ImageLocator adjustedLocator = locator;
|
||||
|
||||
if(adjustedLocator.image)
|
||||
{
|
||||
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);
|
||||
}
|
||||
std::shared_ptr<ScalableImageInstance> result;
|
||||
|
||||
if (adjustedLocator.scalingFactor == 0)
|
||||
{
|
||||
auto scaledLocator = adjustedLocator;
|
||||
scaledLocator.scalingFactor = getScalingFactor();
|
||||
|
||||
return loadImageImpl(scaledLocator)->createImageReference(mode);
|
||||
result = loadImageImpl(scaledLocator)->createImageReference();
|
||||
}
|
||||
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)
|
||||
{
|
||||
auto tmp = getScalePath(path);
|
||||
ImageLocator locator = getLocatorForAnimationFrame(AnimationPath::builtin(tmp.first.getName()), frame, group);
|
||||
locator.preScaledFactor = tmp.second;
|
||||
return loadImage(locator, mode);
|
||||
ImageLocator locator = getLocatorForAnimationFrame(path, frame, group, mode);
|
||||
return loadImage(locator);
|
||||
}
|
||||
|
||||
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
|
||||
{
|
||||
ImageLocator locator(path);
|
||||
return loadImage(locator, mode);
|
||||
ImageLocator locator(path, mode);
|
||||
return loadImage(locator);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -416,7 +332,7 @@ void RenderHandler::addImageListEntries(const EntityService * service)
|
||||
if (imageName.empty())
|
||||
return;
|
||||
|
||||
auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName));
|
||||
auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName), 1, EImageBlitMode::SIMPLE);
|
||||
|
||||
JsonNode entry;
|
||||
entry["file"].String() = imageName;
|
||||
@ -424,7 +340,7 @@ void RenderHandler::addImageListEntries(const EntityService * service)
|
||||
if (index >= layout[group].size())
|
||||
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 SDLImageShared;
|
||||
class ISharedImage;
|
||||
class ScalableImageShared;
|
||||
|
||||
class RenderHandler : public IRenderHandler
|
||||
{
|
||||
@ -25,28 +25,22 @@ class RenderHandler : public IRenderHandler
|
||||
|
||||
std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
|
||||
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::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
|
||||
std::optional<ResourcePath> getPathForScaleFactor(const ResourcePath & path, const std::string & factor);
|
||||
std::pair<ResourcePath, int> getScalePath(const ResourcePath & p);
|
||||
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
|
||||
void initFromJson(AnimationLayoutMap & layout, const JsonNode & config);
|
||||
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path, int scalingFactor, EImageBlitMode mode);
|
||||
void initFromJson(AnimationLayoutMap & layout, const JsonNode & config, EImageBlitMode mode);
|
||||
|
||||
void addImageListEntry(size_t index, size_t group, const std::string & listName, const std::string & imageName);
|
||||
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<const ISharedImage> loadImageFromFile(const ImageLocator & locator);
|
||||
std::shared_ptr<SDLImageShared> loadImageFromFileUncached(const ImageLocator & locator);
|
||||
|
||||
std::shared_ptr<const ISharedImage> transformImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image);
|
||||
std::shared_ptr<const ISharedImage> scaleImage(const ImageLocator & locator, std::shared_ptr<const ISharedImage> image);
|
||||
|
||||
ImageLocator getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group);
|
||||
ImageLocator getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group, EImageBlitMode mode);
|
||||
|
||||
int getScalingFactor() const;
|
||||
|
||||
@ -55,10 +49,12 @@ public:
|
||||
// IRenderHandler implementation
|
||||
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 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<IImage> createImage(SDL_Surface * source) override;
|
||||
|
@ -28,59 +28,6 @@
|
||||
|
||||
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
|
||||
{
|
||||
return dimensions().x;
|
||||
@ -91,12 +38,11 @@ int IImage::height() const
|
||||
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),
|
||||
margins(0, 0),
|
||||
fullSize(0, 0),
|
||||
originalPalette(nullptr),
|
||||
preScaleFactor(preScaleFactor)
|
||||
originalPalette(nullptr)
|
||||
{
|
||||
SDLImageLoader loader(this);
|
||||
data->loadFrame(frame, group, loader);
|
||||
@ -104,12 +50,11 @@ SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group
|
||||
savePalette();
|
||||
}
|
||||
|
||||
SDLImageShared::SDLImageShared(SDL_Surface * from, int preScaleFactor)
|
||||
SDLImageShared::SDLImageShared(SDL_Surface * from)
|
||||
: surf(nullptr),
|
||||
margins(0, 0),
|
||||
fullSize(0, 0),
|
||||
originalPalette(nullptr),
|
||||
preScaleFactor(preScaleFactor)
|
||||
originalPalette(nullptr)
|
||||
{
|
||||
surf = from;
|
||||
if (surf == nullptr)
|
||||
@ -122,12 +67,11 @@ SDLImageShared::SDLImageShared(SDL_Surface * from, int preScaleFactor)
|
||||
fullSize.y = surf->h;
|
||||
}
|
||||
|
||||
SDLImageShared::SDLImageShared(const ImagePath & filename, int preScaleFactor)
|
||||
SDLImageShared::SDLImageShared(const ImagePath & filename)
|
||||
: surf(nullptr),
|
||||
margins(0, 0),
|
||||
fullSize(0, 0),
|
||||
originalPalette(nullptr),
|
||||
preScaleFactor(preScaleFactor)
|
||||
originalPalette(nullptr)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (!surf)
|
||||
@ -292,26 +235,20 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL
|
||||
SDL_SetSurfacePalette(surf, palette);
|
||||
|
||||
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
|
||||
if (mode == EImageBlitMode::OPAQUE || mode == EImageBlitMode::COLORKEY || mode == EImageBlitMode::SIMPLE)
|
||||
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_OPAQUE);
|
||||
else
|
||||
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);
|
||||
// dump heuristics to differentiate tileable UI elements from map object / combat assets
|
||||
if (mode == EImageBlitMode::OPAQUE || mode == EImageBlitMode::COLORKEY || mode == EImageBlitMode::SIMPLE)
|
||||
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_OPAQUE);
|
||||
else
|
||||
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_ALPHA);
|
||||
|
||||
auto ret = std::make_shared<SDLImageShared>(scaled);
|
||||
|
||||
ret->fullSize.x = fullSize.x * factor;
|
||||
ret->fullSize.y = fullSize.y * factor;
|
||||
|
||||
ret->margins.x = (int) round((float)margins.x * factor / preScaleFactor);
|
||||
ret->margins.y = (int) round((float)margins.y * factor / preScaleFactor);
|
||||
ret->margins.x = (int) round((float)margins.x * factor);
|
||||
ret->margins.y = (int) round((float)margins.y * factor);
|
||||
ret->optimizeSurface();
|
||||
|
||||
// erase our own reference
|
||||
@ -340,7 +277,7 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size,
|
||||
else
|
||||
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.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);
|
||||
}
|
||||
|
||||
void SDLImageIndexed::playerColored(PlayerColor player)
|
||||
{
|
||||
graphics->setPlayerPalette(currentPalette, player);
|
||||
}
|
||||
|
||||
bool SDLImageShared::isTransparent(const Point & coords) const
|
||||
{
|
||||
if (surf)
|
||||
@ -384,22 +316,21 @@ bool SDLImageShared::isTransparent(const Point & coords) const
|
||||
|
||||
Rect SDLImageShared::contentRect() const
|
||||
{
|
||||
auto tmpMargins = margins / preScaleFactor;
|
||||
auto tmpSize = Point(surf->w, surf->h) / preScaleFactor;
|
||||
auto tmpMargins = margins;
|
||||
auto tmpSize = Point(surf->w, surf->h);
|
||||
return Rect(tmpMargins, tmpSize);
|
||||
}
|
||||
|
||||
const SDL_Palette * SDLImageShared::getPalette() const
|
||||
{
|
||||
if (!surf)
|
||||
return nullptr;
|
||||
return surf->format->palette;
|
||||
}
|
||||
|
||||
Point SDLImageShared::dimensions() const
|
||||
{
|
||||
return fullSize / preScaleFactor;
|
||||
}
|
||||
|
||||
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);
|
||||
return fullSize;
|
||||
}
|
||||
|
||||
std::shared_ptr<const ISharedImage> SDLImageShared::horizontalFlip() const
|
||||
@ -408,7 +339,7 @@ std::shared_ptr<const ISharedImage> SDLImageShared::horizontalFlip() const
|
||||
return shared_from_this();
|
||||
|
||||
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->margins.x = margins.x;
|
||||
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();
|
||||
|
||||
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->margins.x = fullSize.x - surf->w - margins.x;
|
||||
ret->margins.y = margins.y;
|
||||
@ -445,219 +376,8 @@ void SDLImageShared::savePalette()
|
||||
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()
|
||||
{
|
||||
SDL_FreeSurface(surf);
|
||||
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
|
||||
Point fullSize;
|
||||
|
||||
//pre scaled image
|
||||
int preScaleFactor;
|
||||
|
||||
// Keep the original palette, in order to do color switching operation
|
||||
void savePalette();
|
||||
|
||||
@ -45,11 +42,11 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
|
||||
|
||||
public:
|
||||
//Load image from def file
|
||||
SDLImageShared(const CDefFile *data, size_t frame, size_t group=0, int preScaleFactor=1);
|
||||
SDLImageShared(const CDefFile *data, size_t frame, size_t group=0);
|
||||
//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
|
||||
SDLImageShared(SDL_Surface * from, int preScaleFactor=1);
|
||||
SDLImageShared(SDL_Surface * from);
|
||||
~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;
|
||||
@ -58,7 +55,9 @@ public:
|
||||
Point dimensions() const override;
|
||||
bool isTransparent(const Point & coords) 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> verticalFlip() 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;
|
||||
};
|
||||
|
||||
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::CPicture( const ImagePath & bmpname, const Point & position )
|
||||
: bg(GH.renderHandler().loadImage(bmpname, EImageBlitMode::COLORKEY))
|
||||
CPicture::CPicture( const ImagePath & bmpname, const Point & position, EImageBlitMode mode )
|
||||
: bg(GH.renderHandler().loadImage(bmpname, mode))
|
||||
, needRefresh(false)
|
||||
{
|
||||
pos.x += position.x;
|
||||
@ -74,6 +74,10 @@ CPicture::CPicture( const ImagePath & bmpname, const Point & position )
|
||||
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(bmpname, Point(x,y))
|
||||
{
|
||||
|
@ -21,6 +21,7 @@ class CAnimImage;
|
||||
class CLabel;
|
||||
class CAnimation;
|
||||
class IImage;
|
||||
enum class EImageBlitMode : uint8_t;
|
||||
|
||||
// Image class
|
||||
class CPicture : public CIntObject
|
||||
@ -49,6 +50,7 @@ public:
|
||||
|
||||
/// Loads image from specified file name
|
||||
CPicture(const ImagePath & bmpname);
|
||||
CPicture(const ImagePath & bmpname, const Point & position, EImageBlitMode mode);
|
||||
CPicture(const ImagePath & bmpname, const Point & position);
|
||||
CPicture(const ImagePath & bmpname, int x, int y);
|
||||
|
||||
|
@ -570,9 +570,8 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
|
||||
{
|
||||
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->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
|
||||
pos.w = background->pos.w;
|
||||
pos.h = background->pos.h;
|
||||
|
||||
|
@ -139,9 +139,8 @@ std::shared_ptr<CPicture> CMapOverviewWidget::buildDrawMinimap(const JsonNode &
|
||||
double resize = maxSideLengthSrc / maxSideLengthDst;
|
||||
Point newMinimapSize = Point(minimapRect.w / resize, minimapRect.h / resize);
|
||||
|
||||
Canvas canvasScaled = Canvas(Point(rect.w, rect.h), CanvasScalingPolicy::AUTO);
|
||||
canvasScaled.drawScaled(minimaps[id], Point((rect.w - newMinimapSize.x) / 2, (rect.h - newMinimapSize.y) / 2), newMinimapSize);
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().createImage(canvasScaled.getInternalSurface());
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().createImage(minimaps[id].getInternalSurface());
|
||||
img->scaleTo(newMinimapSize);
|
||||
|
||||
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())
|
||||
return nullptr;
|
||||
|
||||
auto image = std::make_shared<CPicture>(imageName);
|
||||
image->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
|
||||
auto image = std::make_shared<CPicture>(imageName, Point(0,0), EImageBlitMode::OPAQUE);
|
||||
if(playerColored)
|
||||
image->setPlayerColor(LOCPLINT->playerID);
|
||||
return image;
|
||||
@ -116,8 +115,7 @@ void CWindowObject::updateShadow()
|
||||
void CWindowObject::setShadow(bool on)
|
||||
{
|
||||
//size of shadow
|
||||
int sizeOriginal = 8;
|
||||
int size = sizeOriginal * GH.screenHandler().getScalingFactor();
|
||||
int size = 8;
|
||||
|
||||
if(on == !shadowParts.empty())
|
||||
return;
|
||||
@ -182,9 +180,9 @@ void CWindowObject::setShadow(bool on)
|
||||
//FIXME: do something with this points
|
||||
Point shadowStart;
|
||||
if (options & BORDERED)
|
||||
shadowStart = Point(sizeOriginal - 14, sizeOriginal - 14);
|
||||
shadowStart = Point(size - 14, size - 14);
|
||||
else
|
||||
shadowStart = Point(sizeOriginal, sizeOriginal);
|
||||
shadowStart = Point(size, size);
|
||||
|
||||
Point shadowPos;
|
||||
if (options & BORDERED)
|
||||
@ -200,8 +198,8 @@ void CWindowObject::setShadow(bool on)
|
||||
|
||||
//create base 8x8 piece of shadow
|
||||
SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
|
||||
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, (fullsize.x - sizeOriginal) * GH.screenHandler().getScalingFactor(), size);
|
||||
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, (fullsize.y - sizeOriginal) * GH.screenHandler().getScalingFactor());
|
||||
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, (fullsize.x - size), size);
|
||||
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, (fullsize.y - size));
|
||||
|
||||
blitAlphaCol(shadowBottom, 0);
|
||||
blitAlphaRow(shadowRight, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user