1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-19 21:10:12 +02:00

Remove access to internal surface of Canvas

This commit is contained in:
Ivan Savenko 2025-01-16 15:09:03 +00:00
parent 4a600a9d4c
commit 668bf63fc0
34 changed files with 275 additions and 174 deletions

View File

@ -88,6 +88,7 @@ set(vcmiclientcommon_SRCS
render/CBitmapHandler.cpp
render/CDefFile.cpp
render/Canvas.cpp
render/CanvasImage.cpp
render/ColorFilter.cpp
render/Colors.cpp
render/Graphics.cpp
@ -290,6 +291,7 @@ set(vcmiclientcommon_HEADERS
render/CBitmapHandler.h
render/CDefFile.h
render/Canvas.h
render/CanvasImage.h
render/ColorFilter.h
render/Colors.h
render/EFont.h

View File

@ -1153,7 +1153,7 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
if(t)
{
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("ITPA"), t->getTown()->clientInfo.icons[t->hasFort()][false] + 2, 0, EImageBlitMode::OPAQUE);
image->scaleTo(Point(35, 23));
image->scaleTo(Point(35, 23), EScalingAlgorithm::NEAREST);
images.push_back(image);
}
}

View File

@ -22,7 +22,6 @@
#include "../render/Colors.h"
#include "../render/Canvas.h"
#include "../render/Graphics.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../windows/InfoWindows.h"
#include "../../CCallback.h"
@ -178,7 +177,7 @@ void CMinimap::mouseDragged(const Point & cursorPosition, const Point & lastUpda
void CMinimap::showAll(Canvas & to)
{
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), aiShield->pos);
CanvasClipRectGuard guard(to, aiShield->pos);
CIntObject::showAll(to);
if(minimap)

View File

@ -26,7 +26,6 @@
#include "../render/CAnimation.h"
#include "../render/Canvas.h"
#include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/IRenderHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CursorHandler.h"
@ -857,7 +856,7 @@ void BattleFieldController::tick(uint32_t msPassed)
void BattleFieldController::show(Canvas & to)
{
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), pos);
CanvasClipRectGuard guard(to, pos);
renderBattlefield(to);

View File

@ -24,7 +24,6 @@
#include "../render/CAnimation.h"
#include "../render/Canvas.h"
#include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../eventsSDL/InputHandler.h"
#include "../../CCallback.h"
@ -76,7 +75,7 @@ void BasicMapView::tick(uint32_t msPassed)
void BasicMapView::show(Canvas & to)
{
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), pos);
CanvasClipRectGuard guard(to, pos);
render(to, false);
controller->afterRender();
@ -84,7 +83,7 @@ void BasicMapView::show(Canvas & to)
void BasicMapView::showAll(Canvas & to)
{
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), pos);
CanvasClipRectGuard guard(to, pos);
render(to, true);
}

View File

@ -381,12 +381,12 @@ Point CVideoInstance::size()
return dimensions / GH.screenHandler().getScalingFactor();
}
void CVideoInstance::show(const Point & position, Canvas & canvas)
void CVideoInstance::show(const Point & position, SDL_Surface * to)
{
if(sws == nullptr)
throw std::runtime_error("No video to show!");
CSDL_Ext::blitSurface(surface, canvas.getInternalSurface(), position * GH.screenHandler().getScalingFactor());
CSDL_Ext::blitSurface(surface, to, position * GH.screenHandler().getScalingFactor());
}
double FFMpegStream::getCurrentFrameEndTime() const

View File

@ -98,7 +98,7 @@ public:
bool videoEnded() final;
Point size() final;
void show(const Point & position, Canvas & canvas) final;
void show(const Point & position, SDL_Surface * to) final;
void tick(uint32_t msPassed) final;
void activate() final;
void deactivate() final;

View File

@ -11,7 +11,7 @@
#include "../lib/filesystem/ResourcePath.h"
class Canvas;
struct SDL_Surface;
VCMI_LIB_NAMESPACE_BEGIN
class Point;
@ -30,7 +30,7 @@ public:
virtual Point size() = 0;
/// Displays current frame at specified position
virtual void show(const Point & position, Canvas & canvas) = 0;
virtual void show(const Point & position, SDL_Surface * to) = 0;
/// Advances video playback by specified duration
virtual void tick(uint32_t msPassed) = 0;

View File

@ -14,6 +14,7 @@
#include "../render/IImage.h"
#include "../render/IImageLoader.h"
#include "../render/Canvas.h"
#include "../render/CanvasImage.h"
#include "../render/ColorFilter.h"
#include "../render/IRenderHandler.h"
#include "../render/CAnimation.h"
@ -62,7 +63,9 @@ void AssetGenerator::createAdventureOptionsCleanBackground()
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
Canvas canvas = Canvas(Point(575, 585), CanvasScalingPolicy::IGNORE);
auto image = GH.renderHandler().createImage(Point(575, 585), CanvasScalingPolicy::IGNORE);
Canvas canvas = image->getCanvas();
canvas.draw(img, Point(0, 0), Rect(0, 0, 575, 585));
canvas.draw(img, Point(54, 121), Rect(54, 123, 335, 1));
canvas.draw(img, Point(158, 84), Rect(156, 84, 2, 37));
@ -71,8 +74,6 @@ void AssetGenerator::createAdventureOptionsCleanBackground()
canvas.draw(img, Point(53, 567), Rect(53, 520, 339, 3));
canvas.draw(img, Point(53, 520), Rect(53, 264, 339, 47));
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
}
@ -90,7 +91,8 @@ void AssetGenerator::createBigSpellBook()
auto locator = ImageLocator(ImagePath::builtin("SpelBack"), EImageBlitMode::OPAQUE);
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
Canvas canvas = image->getCanvas();
// edges
canvas.draw(img, Point(0, 0), Rect(15, 38, 90, 45));
canvas.draw(img, Point(0, 460), Rect(15, 400, 90, 141));
@ -133,8 +135,6 @@ void AssetGenerator::createBigSpellBook()
canvas.draw(img, Point(575, 465), Rect(417, 406, 37, 45));
canvas.draw(img, Point(667, 465), Rect(478, 406, 37, 47));
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
}
@ -233,7 +233,8 @@ void AssetGenerator::createCampaignBackground()
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
Canvas canvas = image->getCanvas();
canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
@ -263,8 +264,6 @@ void AssetGenerator::createCampaignBackground()
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());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
}
@ -288,7 +287,8 @@ void AssetGenerator::createChroniclesCampaignImages()
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
Canvas canvas = Canvas(Point(200, 116), CanvasScalingPolicy::IGNORE);
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
Canvas canvas = image->getCanvas();
switch (i)
{
@ -327,8 +327,6 @@ void AssetGenerator::createChroniclesCampaignImages()
break;
}
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
}
}
@ -412,9 +410,9 @@ void AssetGenerator::createPaletteShiftedSprites()
}
}
Canvas canvas = Canvas(Point(32, 32), CanvasScalingPolicy::IGNORE);
auto image = GH.renderHandler().createImage(Point(32, 32), CanvasScalingPolicy::IGNORE);
Canvas canvas = image->getCanvas();
canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
JsonNode node(JsonMap{

View File

@ -11,6 +11,7 @@
#include "Canvas.h"
#include "../gui/CGuiHandler.h"
#include "../media/IVideoPlayer.h"
#include "../render/IRenderHandler.h"
#include "../render/IScreenHandler.h"
#include "../renderSDL/SDL_Extensions.h"
@ -102,6 +103,16 @@ Canvas::~Canvas()
SDL_FreeSurface(surface);
}
void Canvas::draw(IVideoInstance & video, const Point & pos)
{
video.show(pos, surface);
}
void Canvas::draw(const IImage& image, const Point & pos)
{
image.draw(surface, transformPos(pos), nullptr, getScalingFactor());
}
void Canvas::draw(const std::shared_ptr<IImage>& image, const Point & pos)
{
assert(image);
@ -222,12 +233,18 @@ void Canvas::fillTexture(const std::shared_ptr<IImage>& image)
}
}
SDL_Surface * Canvas::getInternalSurface() const
{
return surface;
}
Rect Canvas::getRenderArea() const
{
return renderArea;
}
CanvasClipRectGuard::CanvasClipRectGuard(Canvas & canvas, const Rect & rect): surf(canvas.surface)
{
CSDL_Ext::getClipRect(surf, oldRect);
CSDL_Ext::setClipRect(surf, rect * GH.screenHandler().getScalingFactor());
}
CanvasClipRectGuard::~CanvasClipRectGuard()
{
CSDL_Ext::setClipRect(surf, oldRect);
}

View File

@ -15,6 +15,7 @@
struct SDL_Surface;
class IImage;
class IVideoInstance;
enum EFonts : int8_t;
enum class CanvasScalingPolicy
@ -27,6 +28,8 @@ enum class CanvasScalingPolicy
/// Class that represents surface for drawing on
class Canvas
{
friend class CanvasClipRectGuard;
/// Upscaler awareness. Must be first member for initialization
CanvasScalingPolicy scalingPolicy;
@ -72,6 +75,9 @@ public:
/// renders image onto this canvas at specified position
void draw(const std::shared_ptr<IImage>& image, const Point & pos);
void draw(const IImage& image, const Point & pos);
void draw(IVideoInstance & video, const Point & pos);
/// renders section of image bounded by sourceRect at specified position
void draw(const std::shared_ptr<IImage>& image, const Point & pos, const Rect & sourceRect);
@ -114,9 +120,16 @@ public:
int getScalingFactor() const;
/// Compatibility method. AVOID USAGE. To be removed once SDL abstraction layer is finished.
SDL_Surface * getInternalSurface() const;
/// get the render area
Rect getRenderArea() const;
};
class CanvasClipRectGuard : boost::noncopyable
{
SDL_Surface * surf;
Rect oldRect;
public:
CanvasClipRectGuard(Canvas & canvas, const Rect & rect);
~CanvasClipRectGuard();
};

View File

@ -0,0 +1,61 @@
/*
* CanvasImage.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 "CanvasImage.h"
#include "../gui/CGuiHandler.h"
#include "../render/IScreenHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include <SDL_image.h>
#include <SDL_surface.h>
CanvasImage::CanvasImage(const Point & size, CanvasScalingPolicy scalingPolicy)
: surface(CSDL_Ext::newSurface(scalingPolicy == CanvasScalingPolicy::IGNORE ? size : (size * GH.screenHandler().getScalingFactor())))
, scalingPolicy(scalingPolicy)
{
}
void CanvasImage::draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const
{
if(src)
CSDL_Ext::blitSurface(surface, *src, where, pos);
else
CSDL_Ext::blitSurface(surface, where, pos);
}
void CanvasImage::scaleTo(const Point & size, EScalingAlgorithm algorithm)
{
Point scaledSize = scalingPolicy == CanvasScalingPolicy::IGNORE ? size : (size * GH.screenHandler().getScalingFactor());
auto newSurface = CSDL_Ext::scaleSurface(surface, scaledSize.x, scaledSize.y, algorithm);
SDL_FreeSurface(surface);
surface = newSurface;
}
void CanvasImage::exportBitmap(const boost::filesystem::path & path) const
{
IMG_SavePNG(surface, path.string().c_str());
}
Canvas CanvasImage::getCanvas()
{
return Canvas::createFromSurface(surface, scalingPolicy);
}
Rect CanvasImage::contentRect() const
{
return Rect(Point(0, 0), dimensions());
}
Point CanvasImage::dimensions() const
{
return {surface->w, surface->h};
}

View File

@ -0,0 +1,41 @@
/*
* CanvasImage.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 "IImage.h"
#include "Canvas.h"
class CanvasImage : public IImage
{
public:
CanvasImage(const Point & size, CanvasScalingPolicy scalingPolicy);
Canvas getCanvas();
void draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const override;
void scaleTo(const Point & size, EScalingAlgorithm algorithm) override;
void exportBitmap(const boost::filesystem::path & path) const override;
Rect contentRect() const override;
Point dimensions() const override;
//no-op methods
bool isTransparent(const Point & coords) const override{ return false;};
void setAlpha(uint8_t value) override{};
void playerColored(const PlayerColor & player) override{};
void setOverlayColor(const ColorRGBA & color) override{};
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override{};
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override{};
private:
SDL_Surface * surface;
CanvasScalingPolicy scalingPolicy;
};

View File

@ -62,6 +62,14 @@ enum class EImageBlitMode : uint8_t
ONLY_OVERLAY,
};
enum class EScalingAlgorithm : int8_t
{
NEAREST,
BILINEAR,
XBRZ_OPAQUE, // xbrz, image edges are considered to have same color as pixel inside image. Only for integer scaling
XBRZ_ALPHA // xbrz, image edges are considered to be transparent. Only for integer scaling
};
/// Base class for images for use in client code.
/// This class represents current state of image, with potential transformations applied, such as player coloring
class IImage
@ -70,12 +78,12 @@ public:
//draws image on surface "where" at position
virtual void draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const = 0;
virtual void scaleTo(const Point & size) = 0;
virtual void scaleTo(const Point & size, EScalingAlgorithm algorithm) = 0;
virtual void exportBitmap(const boost::filesystem::path & path) const = 0;
//Change palette to specific player
virtual void playerColored(PlayerColor player) = 0;
virtual void playerColored(const PlayerColor & player) = 0;
//test transparency of specific pixel
virtual bool isTransparent(const Point & coords) const = 0;

View File

@ -20,8 +20,10 @@ struct SDL_Surface;
class IFont;
class IImage;
class CAnimation;
class CanvasImage;
class SDLImageShared;
enum class EImageBlitMode : uint8_t;
enum class CanvasScalingPolicy;
enum EFonts : int8_t;
class IRenderHandler : public boost::noncopyable
@ -40,9 +42,8 @@ public:
/// 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;
/// Creates image which can be used as target for drawing on
virtual std::shared_ptr<CanvasImage> createImage(const Point & size, CanvasScalingPolicy scalingPolicy) = 0;
/// Loads animation using given path
virtual std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) = 0;

View File

@ -14,6 +14,7 @@
#include "../CGameInfo.h"
#include "../gui/CGuiHandler.h"
#include "../render/Colors.h"
#include "../render/IImage.h"
#include "../render/IScreenHandler.h"
#include "../../lib/CConfigHandler.h"

View File

@ -60,7 +60,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), nullptr, GH.screenHandler().getScalingFactor());
auto cursorSurfaceScaled = CSDL_Ext::scaleSurface(cursorSurface, cursorDimensionsScaled.x, cursorDimensionsScaled.y );
auto cursorSurfaceScaled = CSDL_Ext::scaleSurface(cursorSurface, cursorDimensionsScaled.x, cursorDimensionsScaled.y, EScalingAlgorithm::BILINEAR );
auto oldCursor = cursor;
cursor = SDL_CreateColorCursor(cursorSurfaceScaled, pivotOffsetScaled.x, pivotOffsetScaled.y);

View File

@ -17,6 +17,7 @@
#include "../gui/CGuiHandler.h"
#include "../render/CAnimation.h"
#include "../render/CanvasImage.h"
#include "../render/CDefFile.h"
#include "../render/Colors.h"
#include "../render/ColorFilter.h"
@ -308,14 +309,9 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageB
return loadImage(locator);
}
std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
std::shared_ptr<CanvasImage> RenderHandler::createImage(const Point & size, CanvasScalingPolicy scalingPolicy)
{
auto baseImage = std::make_shared<SDLImageShared>(source);
SharedImageLocator locator;
locator.layer = EImageBlitMode::SIMPLE;
auto scalableImage = std::make_shared<ScalableImageShared>(locator, baseImage);
return scalableImage->createImageReference();
return std::make_shared<CanvasImage>(size, scalingPolicy);
}
std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)

View File

@ -57,7 +57,7 @@ public:
std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) override;
std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
std::shared_ptr<CanvasImage> createImage(const Point & size, CanvasScalingPolicy scalingPolicy) override;
/// Returns font with specified identifer
std::shared_ptr<const IFont> loadFont(EFonts font) override;

View File

@ -268,7 +268,7 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size,
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
auto scaled = CSDL_Ext::scaleSurface(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY));
auto scaled = CSDL_Ext::scaleSurface(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY), EScalingAlgorithm::BILINEAR);
if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point
CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]);

View File

@ -14,6 +14,7 @@
#include "../gui/CGuiHandler.h"
#include "../render/Graphics.h"
#include "../render/IImage.h"
#include "../render/IScreenHandler.h"
#include "../render/Colors.h"
#include "../CMT.h"
@ -633,7 +634,7 @@ void CSDL_Ext::convertToGrayscale( SDL_Surface * surf, const Rect & rect )
// scaling via bilinear interpolation algorithm.
// NOTE: best results are for scaling in range 50%...200%.
// And upscaling looks awful right now - should be fixed somehow
SDL_Surface * CSDL_Ext::scaleSurface(SDL_Surface * surf, int width, int height)
SDL_Surface * CSDL_Ext::scaleSurface(SDL_Surface * surf, int width, int height, EScalingAlgorithm algorithm)
{
if(!surf || !width || !height)
return nullptr;
@ -644,11 +645,14 @@ SDL_Surface * CSDL_Ext::scaleSurface(SDL_Surface * surf, int width, int height)
SDL_Surface * intermediate = SDL_ConvertSurface(surf, screen->format, 0);
SDL_Surface * ret = newSurface(Point(width, height), intermediate);
#if SDL_VERSION_ATLEAST(2,0,16)
SDL_SoftStretchLinear(intermediate, nullptr, ret, nullptr);
#else
SDL_SoftStretch(intermediate, nullptr, ret, nullptr);
#endif
const uint32_t * srcPixels = static_cast<const uint32_t*>(intermediate->pixels);
uint32_t * dstPixels = static_cast<uint32_t*>(ret->pixels);
if (algorithm == EScalingAlgorithm::NEAREST)
xbrz::nearestNeighborScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
else
xbrz::bilinearScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
SDL_FreeSurface(intermediate);
return ret;
@ -799,10 +803,5 @@ void CSDL_Ext::getClipRect(SDL_Surface * src, Rect & other)
other = CSDL_Ext::fromSDL(rect);
}
int CSDL_Ext::CClipRectGuard::getScalingFactor() const
{
return GH.screenHandler().getScalingFactor();
}
template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<3>(int, int);
template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<4>(int, int);

View File

@ -18,6 +18,7 @@ struct SDL_Renderer;
struct SDL_Texture;
struct SDL_Surface;
struct SDL_Color;
enum class EScalingAlgorithm : int8_t;
VCMI_LIB_NAMESPACE_BEGIN
@ -27,14 +28,6 @@ class Point;
VCMI_LIB_NAMESPACE_END
enum class EScalingAlgorithm : int8_t
{
NEAREST,
BILINEAR,
XBRZ_OPAQUE, // xbrz, image edges are considered to have same color as pixel inside image
XBRZ_ALPHA // xbrz, image edges are considered to be transparent
};
namespace CSDL_Ext
{
@ -99,7 +92,7 @@ using TColorPutterAlpha = void (*)(uint8_t *&, const uint8_t &, const uint8_t &,
SDL_Surface * createSurfaceWithBpp(int width, int height); //create surface with give bits per pixels value
// bilinear filtering. Always returns rgba surface
SDL_Surface * scaleSurface(SDL_Surface * surf, int width, int height);
SDL_Surface * scaleSurface(SDL_Surface * surf, int width, int height, EScalingAlgorithm scaler);
SDL_Surface * scaleSurfaceIntegerFactor(SDL_Surface * surf, int factor, EScalingAlgorithm scaler);
template<int bpp>

View File

@ -20,6 +20,7 @@
#include "../render/Graphics.h"
#include "../render/IRenderHandler.h"
#include "../render/IScreenHandler.h"
#include "../render/CanvasImage.h"
#include "../../lib/constants/EntityIdentifiers.h"
@ -292,9 +293,15 @@ ScalableImageInstance::ScalableImageInstance(const std::shared_ptr<ScalableImage
assert(image);
}
void ScalableImageInstance::scaleTo(const Point & size)
void ScalableImageInstance::scaleTo(const Point & size, EScalingAlgorithm algorithm)
{
assert(0);
scaledImage = nullptr;
auto newScaledImage = GH.renderHandler().createImage(dimensions(), CanvasScalingPolicy::AUTO);
newScaledImage->getCanvas().draw(*this, Point(0, 0));
newScaledImage->scaleTo(size, algorithm);
scaledImage = newScaledImage;
}
void ScalableImageInstance::exportBitmap(const boost::filesystem::path & path) const
@ -314,6 +321,8 @@ Rect ScalableImageInstance::contentRect() const
Point ScalableImageInstance::dimensions() const
{
if (scaledImage)
return scaledImage->dimensions() / GH.screenHandler().getScalingFactor();
return image->dimensions();
}
@ -324,6 +333,9 @@ void ScalableImageInstance::setAlpha(uint8_t value)
void ScalableImageInstance::draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const
{
if (scaledImage)
scaledImage->draw(where, pos, src, scalingFactor);
else
image->draw(where, pos, src, parameters, scalingFactor);
}
@ -335,7 +347,7 @@ void ScalableImageInstance::setOverlayColor(const ColorRGBA & color)
parameters.setOverlayColor(image->getPalette(), color);
}
void ScalableImageInstance::playerColored(PlayerColor player)
void ScalableImageInstance::playerColored(const PlayerColor & player)
{
parameters.player = player;

View File

@ -18,6 +18,7 @@
struct SDL_Palette;
class ScalableImageInstance;
class CanvasImage;
struct ScalableImageParameters : boost::noncopyable
{
@ -99,6 +100,7 @@ class ScalableImageInstance final : public IImage
friend class ScalableImageShared;
std::shared_ptr<ScalableImageShared> image;
std::shared_ptr<CanvasImage> scaledImage;
ScalableImageParameters parameters;
EImageBlitMode blitMode;
@ -106,7 +108,7 @@ class ScalableImageInstance final : public IImage
public:
ScalableImageInstance(const std::shared_ptr<ScalableImageShared> & image, EImageBlitMode blitMode);
void scaleTo(const Point & size) override;
void scaleTo(const Point & size, EScalingAlgorithm algorithm) override;
void exportBitmap(const boost::filesystem::path & path) const override;
bool isTransparent(const Point & coords) const override;
Rect contentRect() const override;
@ -114,7 +116,7 @@ public:
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 playerColored(const PlayerColor & player) override;
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override;
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;

View File

@ -11,13 +11,14 @@
#include "StdInc.h"
#include "ScreenHandler.h"
#include "../eventsSDL/NotificationHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/WindowHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "CMT.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/constants/StringConstants.h"
#include "../gui/CGuiHandler.h"
#include "../eventsSDL/NotificationHandler.h"
#include "../gui/WindowHandler.h"
#include "CMT.h"
#include "SDL_Extensions.h"
#ifdef VCMI_ANDROID
#include "../lib/CAndroidVMHelper.h"

View File

@ -13,7 +13,6 @@
#include "MiscWidgets.h"
#include "../gui/CGuiHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/AssetGenerator.h"
#include "../render/IImage.h"
#include "../render/IRenderHandler.h"
@ -122,7 +121,7 @@ void CPicture::setAlpha(uint8_t value)
void CPicture::scaleTo(Point size)
{
bg->scaleTo(size);
bg->scaleTo(size, EScalingAlgorithm::BILINEAR);
pos.w = bg->width();
pos.h = bg->height();
@ -164,7 +163,7 @@ CFilledTexture::CFilledTexture(const ImagePath & imageName, Rect position, Rect
void CFilledTexture::showAll(Canvas & to)
{
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), pos);
CanvasClipRectGuard guard(to, pos);
for (int y=pos.top(); y < pos.bottom(); y+= imageArea.h)
{
@ -270,7 +269,7 @@ void CAnimImage::showAll(Canvas & to)
if(auto img = anim->getImage(targetFrame, group))
{
if(isScaled())
img->scaleTo(scaledSize);
img->scaleTo(scaledSize, EScalingAlgorithm::BILINEAR);
to.draw(img, pos.topLeft());
}

View File

@ -18,7 +18,6 @@
#include "../windows/CMessage.h"
#include "../windows/InfoWindows.h"
#include "../adventureMap/CInGameConsole.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/Canvas.h"
#include "../render/Graphics.h"
#include "../render/IFont.h"
@ -298,7 +297,7 @@ void CMultiLineLabel::showAll(Canvas & to)
Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * fontPtr->getLineHeight());
Point lineSize = Point(getTextLocation().w, fontPtr->getLineHeight());
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), getTextLocation()); // to properly trim text that is too big to fit
CanvasClipRectGuard guard(to, getTextLocation()); // to properly trim text that is too big to fit
for(int i = beginLine; i < std::min(totalLines, endLine); i++)
{

View File

@ -86,7 +86,7 @@ void VideoWidgetBase::playVideo(const VideoPath & fileToPlay)
void VideoWidgetBase::show(Canvas & to)
{
if(videoInstance)
videoInstance->show(pos.topLeft(), to);
to.draw(*videoInstance, pos.topLeft());
if(subTitle)
subTitle->showAll(to);
}
@ -162,7 +162,7 @@ void VideoWidgetBase::deactivate()
void VideoWidgetBase::showAll(Canvas & to)
{
if(videoInstance)
videoInstance->show(pos.topLeft(), to);
to.draw(*videoInstance, pos.topLeft());
if(subTitle)
subTitle->showAll(to);
}

View File

@ -973,7 +973,7 @@ void CCastleBuildings::enterCastleGate(BuildingID building)
if(settings["general"]["enableUiEnhancements"].Bool())
{
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("ITPA"), t->getTown()->clientInfo.icons[t->hasFort()][false] + 2, 0, EImageBlitMode::OPAQUE);
image->scaleTo(Point(35, 23));
image->scaleTo(Point(35, 23), EScalingAlgorithm::NEAREST);
images.push_back(image);
}
}

View File

@ -20,7 +20,7 @@
#include "../widgets/TextControls.h"
#include "../windows/GUIClasses.h"
#include "../windows/InfoWindows.h"
#include "../render/Canvas.h"
#include "../render/CanvasImage.h"
#include "../render/IImage.h"
#include "../render/IRenderHandler.h"
#include "../render/Graphics.h"
@ -58,9 +58,10 @@ CMapOverview::CMapOverview(const std::string & mapName, const std::string & file
fitToScreen(10);
}
Canvas CMapOverviewWidget::createMinimapForLayer(std::unique_ptr<CMap> & map, int layer) const
std::shared_ptr<CanvasImage> CMapOverviewWidget::createMinimapForLayer(std::unique_ptr<CMap> & map, int layer) const
{
Canvas canvas = Canvas(Point(map->width, map->height), CanvasScalingPolicy::IGNORE);
auto canvasImage = GH.renderHandler().createImage(Point(map->width, map->height), CanvasScalingPolicy::IGNORE);
auto canvas = canvasImage->getCanvas();
for (int y = 0; y < map->height; ++y)
for (int x = 0; x < map->width; ++x)
@ -91,12 +92,12 @@ Canvas CMapOverviewWidget::createMinimapForLayer(std::unique_ptr<CMap> & map, in
canvas.drawPoint(Point(x, y), color);
}
return canvas;
return canvasImage;
}
std::vector<Canvas> CMapOverviewWidget::createMinimaps(ResourcePath resource) const
std::vector<std::shared_ptr<CanvasImage>> CMapOverviewWidget::createMinimaps(ResourcePath resource) const
{
auto ret = std::vector<Canvas>();
std::vector<std::shared_ptr<CanvasImage>> ret;
CMapService mapService;
std::unique_ptr<CMap> map;
@ -113,9 +114,9 @@ std::vector<Canvas> CMapOverviewWidget::createMinimaps(ResourcePath resource) co
return createMinimaps(map);
}
std::vector<Canvas> CMapOverviewWidget::createMinimaps(std::unique_ptr<CMap> & map) const
std::vector<std::shared_ptr<CanvasImage>> CMapOverviewWidget::createMinimaps(std::unique_ptr<CMap> & map) const
{
auto ret = std::vector<Canvas>();
std::vector<std::shared_ptr<CanvasImage>> ret;
for(int i = 0; i < (map->twoLevel ? 2 : 1); i++)
ret.push_back(createMinimapForLayer(map, i));
@ -133,16 +134,15 @@ std::shared_ptr<CPicture> CMapOverviewWidget::buildDrawMinimap(const JsonNode &
if(id >= minimaps.size())
return nullptr;
Rect minimapRect = minimaps[id].getRenderArea();
double maxSideLengthSrc = std::max(minimapRect.w, minimapRect.h);
Point minimapRect = minimaps[id]->dimensions();
double maxSideLengthSrc = std::max(minimapRect.x, minimapRect.y);
double maxSideLengthDst = std::max(rect.w, rect.h);
double resize = maxSideLengthSrc / maxSideLengthDst;
Point newMinimapSize = Point(minimapRect.w / resize, minimapRect.h / resize);
Point newMinimapSize = Point(minimapRect.x / resize, minimapRect.y / resize);
std::shared_ptr<IImage> img = GH.renderHandler().createImage(minimaps[id].getInternalSurface());
img->scaleTo(newMinimapSize);
minimaps[id]->scaleTo(newMinimapSize, EScalingAlgorithm::NEAREST); // for sharp-looking minimap
return std::make_shared<CPicture>(img, Point(rect.x, rect.y));
return std::make_shared<CPicture>(minimaps[id], Point(rect.x, rect.y));
}
CMapOverviewWidget::CMapOverviewWidget(CMapOverview& parent):

View File

@ -22,7 +22,7 @@ class CPicture;
class CFilledTexture;
class CTextBox;
class IImage;
class Canvas;
class CanvasImage;
class TransparentFilledRectangle;
enum class ESelectionScreen : ui8;
@ -33,11 +33,11 @@ class CMapOverviewWidget : public InterfaceObjectConfigurable
CMapOverview& p;
bool drawPlayerElements;
std::vector<Canvas> minimaps;
std::vector<std::shared_ptr<CanvasImage>> minimaps;
Canvas createMinimapForLayer(std::unique_ptr<CMap> & map, int layer) const;
std::vector<Canvas> createMinimaps(ResourcePath resource) const;
std::vector<Canvas> createMinimaps(std::unique_ptr<CMap> & map) const;
std::shared_ptr<CanvasImage> createMinimapForLayer(std::unique_ptr<CMap> & map, int layer) const;
std::vector<std::shared_ptr<CanvasImage>> createMinimaps(ResourcePath resource) const;
std::vector<std::shared_ptr<CanvasImage>> createMinimaps(std::unique_ptr<CMap> & map) const;
std::shared_ptr<CPicture> buildDrawMinimap(const JsonNode & config) const;
public:

View File

@ -21,7 +21,6 @@
#include "../adventureMap/AdventureMapInterface.h"
#include "../adventureMap/CMinimap.h"
#include "../render/Canvas.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
#include "../../lib/CArtHandler.h"
@ -61,7 +60,7 @@ void CQuestIcon::clickPressed(const Point & cursorPosition)
void CQuestIcon::showAll(Canvas & to)
{
CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), parent->pos);
CanvasClipRectGuard guard(to, parent->pos);
CAnimImage::showAll(to);
}

View File

@ -23,6 +23,7 @@
#include "../render/IScreenHandler.h"
#include "../render/IRenderHandler.h"
#include "../render/Canvas.h"
#include "../render/CanvasImage.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
@ -128,55 +129,6 @@ void CWindowObject::setShadow(bool on)
if(on)
{
//helper to set last row
auto blitAlphaRow = [](SDL_Surface *surf, size_t row)
{
uint8_t * ptr = (uint8_t*)surf->pixels + surf->pitch * (row);
for (size_t i=0; i< surf->w; i++)
{
Channels::px<4>::a.set(ptr, 128);
ptr+=4;
}
};
// helper to set last column
auto blitAlphaCol = [](SDL_Surface *surf, size_t col)
{
uint8_t * ptr = (uint8_t*)surf->pixels + 4 * (col);
for (size_t i=0; i< surf->h; i++)
{
Channels::px<4>::a.set(ptr, 128);
ptr+= surf->pitch;
}
};
static SDL_Surface * shadowCornerTempl = nullptr;
static SDL_Surface * shadowBottomTempl = nullptr;
static SDL_Surface * shadowRightTempl = nullptr;
//one-time initialization
if(!shadowCornerTempl)
{
//create "template" surfaces
shadowCornerTempl = CSDL_Ext::createSurfaceWithBpp<4>(size, size);
shadowBottomTempl = CSDL_Ext::createSurfaceWithBpp<4>(1, size);
shadowRightTempl = CSDL_Ext::createSurfaceWithBpp<4>(size, 1);
//fill with shadow body color
CSDL_Ext::fillSurface(shadowCornerTempl, { 0, 0, 0, 192 } );
CSDL_Ext::fillSurface(shadowBottomTempl, { 0, 0, 0, 192 } );
CSDL_Ext::fillSurface(shadowRightTempl, { 0, 0, 0, 192 } );
//fill last row and column with more transparent color
blitAlphaCol(shadowRightTempl , size-1);
blitAlphaCol(shadowCornerTempl, size-1);
blitAlphaRow(shadowBottomTempl, size-1);
blitAlphaRow(shadowCornerTempl, size-1);
}
//FIXME: do something with this points
Point shadowStart;
if (options & BORDERED)
@ -196,26 +148,36 @@ void CWindowObject::setShadow(bool on)
else
fullsize = Point(pos.w, pos.h);
//create base 8x8 piece of shadow
SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, (fullsize.x - size), size);
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, (fullsize.y - size));
Point sizeCorner(size, size);
Point sizeRight(fullsize.x - size, size);
Point sizeBottom(size, fullsize.y - size);
blitAlphaCol(shadowBottom, 0);
blitAlphaRow(shadowRight, 0);
//create base 8x8 piece of shadow
auto imageCorner = GH.renderHandler().createImage(sizeCorner, CanvasScalingPolicy::AUTO);
auto imageRight = GH.renderHandler().createImage(sizeRight, CanvasScalingPolicy::AUTO);
auto imageBottom = GH.renderHandler().createImage(sizeBottom, CanvasScalingPolicy::AUTO);
Canvas canvasCorner = imageCorner->getCanvas();
Canvas canvasRight = imageRight->getCanvas();
Canvas canvasBottom = imageBottom->getCanvas();
canvasCorner.drawColor(Rect(Point(0,0), sizeCorner), { 0, 0, 0, 128 });
canvasRight.drawColor(Rect(Point(0,0), sizeRight), { 0, 0, 0, 128 });
canvasBottom.drawColor(Rect(Point(0,0), sizeBottom), { 0, 0, 0, 128 });
canvasCorner.drawColor(Rect(Point(0,0), sizeCorner - Point(1,1)), { 0, 0, 0, 192 });
canvasRight.drawColor(Rect(Point(0,0), sizeRight - Point(0,1)), { 0, 0, 0, 192 });
canvasBottom.drawColor(Rect(Point(0,0), sizeBottom - Point(1,0)), { 0, 0, 0, 192 });
//generate "shadow" object with these 3 pieces in it
{
OBJECT_CONSTRUCTION;
shadowParts.push_back(std::make_shared<CPicture>( GH.renderHandler().createImage(shadowCorner), Point(shadowPos.x, shadowPos.y)));
shadowParts.push_back(std::make_shared<CPicture>( GH.renderHandler().createImage(shadowRight ), Point(shadowPos.x, shadowStart.y)));
shadowParts.push_back(std::make_shared<CPicture>( GH.renderHandler().createImage(shadowBottom), Point(shadowStart.x, shadowPos.y)));
shadowParts.push_back(std::make_shared<CPicture>( imageCorner, Point(shadowPos.x, shadowPos.y)));
shadowParts.push_back(std::make_shared<CPicture>( imageRight, Point(shadowStart.x, shadowPos.y)));
shadowParts.push_back(std::make_shared<CPicture>( imageBottom, Point(shadowPos.x, shadowStart.y)));
}
SDL_FreeSurface(shadowCorner);
SDL_FreeSurface(shadowBottom);
SDL_FreeSurface(shadowRight);
}
}

View File

@ -236,7 +236,7 @@ void CWindowWithArtifacts::setCursorAnimation(const CArtifactInstance & artInst)
{
assert(artInst.getScrollSpellID().num >= 0);
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("spellscr"), artInst.getScrollSpellID().num, 0, EImageBlitMode::COLORKEY);
image->scaleTo(Point(44,34));
image->scaleTo(Point(44,34), EScalingAlgorithm::BILINEAR);
CCS->curh->dragAndDropCursor(image);
}