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

Moved image scaling & optimization logic to separate classes

This commit is contained in:
Ivan Savenko
2025-01-21 16:36:57 +00:00
parent 68bac73632
commit 391986e0ba
14 changed files with 345 additions and 222 deletions

View File

@@ -104,6 +104,7 @@ set(vcmiclientcommon_SRCS
renderSDL/RenderHandler.cpp
renderSDL/SDLImage.cpp
renderSDL/SDLImageLoader.cpp
renderSDL/SDLImageScaler.cpp
renderSDL/SDLRWwrapper.cpp
renderSDL/ScreenHandler.cpp
renderSDL/SDL_Extensions.cpp
@@ -313,6 +314,7 @@ set(vcmiclientcommon_HEADERS
renderSDL/RenderHandler.h
renderSDL/SDLImage.h
renderSDL/SDLImageLoader.h
renderSDL/SDLImageScaler.h
renderSDL/SDLRWwrapper.h
renderSDL/ScreenHandler.h
renderSDL/SDL_Extensions.h

View File

@@ -13,6 +13,7 @@
#include "../gui/CGuiHandler.h"
#include "../render/IScreenHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../renderSDL/SDLImageScaler.h"
#include <SDL_image.h>
#include <SDL_surface.h>
@@ -35,9 +36,10 @@ void CanvasImage::scaleTo(const Point & size, EScalingAlgorithm algorithm)
{
Point scaledSize = size * GH.screenHandler().getScalingFactor();
auto newSurface = CSDL_Ext::scaleSurface(surface, scaledSize.x, scaledSize.y, algorithm);
SDLImageScaler scaler(surface);
scaler.scaleSurface(scaledSize, algorithm);
SDL_FreeSurface(surface);
surface = newSurface;
surface = scaler.acquireResultSurface();
}
void CanvasImage::exportBitmap(const boost::filesystem::path & path) const

View File

@@ -11,6 +11,8 @@
#include "CBitmapFont.h"
#include "SDL_Extensions.h"
#include "SDLImageScaler.h"
#include "../CGameInfo.h"
#include "../gui/CGuiHandler.h"
#include "../render/Colors.h"
@@ -207,9 +209,10 @@ CBitmapFont::CBitmapFont(const std::string & filename):
auto filterName = settings["video"]["fontUpscalingFilter"].String();
EScalingAlgorithm algorithm = filterNameToEnum.at(filterName);
auto scaledSurface = CSDL_Ext::scaleSurfaceIntegerFactor(atlasImage, GH.screenHandler().getScalingFactor(), algorithm);
SDLImageScaler scaler(atlasImage);
scaler.scaleSurfaceIntegerFactor(GH.screenHandler().getScalingFactor(), algorithm);
SDL_FreeSurface(atlasImage);
atlasImage = scaledSurface;
atlasImage = scaler.acquireResultSurface();
}
logGlobal->debug("Loaded BMP font: '%s', height %d, ascent %d",

View File

@@ -12,6 +12,7 @@
#include "CursorHardware.h"
#include "SDL_Extensions.h"
#include "SDLImageScaler.h"
#include "../gui/CGuiHandler.h"
#include "../render/IScreenHandler.h"
@@ -60,7 +61,10 @@ 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, EScalingAlgorithm::BILINEAR );
SDLImageScaler scaler(cursorSurface);
scaler.scaleSurface(cursorDimensionsScaled, EScalingAlgorithm::BILINEAR);
SDL_Surface * cursorSurfaceScaled = scaler.acquireResultSurface();
auto oldCursor = cursor;
cursor = SDL_CreateColorCursor(cursorSurfaceScaled, pivotOffsetScaled.x, pivotOffsetScaled.y);

View File

@@ -248,10 +248,11 @@ std::shared_ptr<SDLImageShared> RenderHandler::loadScaledImage(const ImageLocato
pathToLoad = *remappedLocator.image;
}
if(!locator.image)
return nullptr;
if(locator.image)
pathToLoad = *locator.image;
pathToLoad = *locator.image;
if (pathToLoad.empty())
return nullptr;
std::string imagePathString = pathToLoad.getName();

View File

@@ -11,14 +11,12 @@
#include "SDLImage.h"
#include "SDLImageLoader.h"
#include "SDLImageScaler.h"
#include "SDL_Extensions.h"
#include "../render/ColorFilter.h"
#include "../render/Colors.h"
#include "../render/CBitmapHandler.h"
#include "../render/CDefFile.h"
#include "../render/Graphics.h"
#include "../xBRZ/xbrz.h"
#include "../gui/CGuiHandler.h"
#include "../render/IScreenHandler.h"
@@ -145,82 +143,14 @@ void SDLImageShared::optimizeSurface()
if (!surf)
return;
int left = surf->w;
int top = surf->h;
int right = 0;
int bottom = 0;
SDLImageOptimizer optimizer(surf, Rect(margins, fullSize));
// locate fully-transparent area around image
// H3 hadles this on format level, but mods or images scaled in runtime do not
if (surf->format->palette)
{
for (int y = 0; y < surf->h; ++y)
{
const uint8_t * row = static_cast<uint8_t *>(surf->pixels) + y * surf->pitch;
for (int x = 0; x < surf->w; ++x)
{
if (row[x] != 0)
{
// opaque or can be opaque (e.g. disabled shadow)
top = std::min(top, y);
left = std::min(left, x);
right = std::max(right, x);
bottom = std::max(bottom, y);
}
}
}
}
else
{
for (int y = 0; y < surf->h; ++y)
{
for (int x = 0; x < surf->w; ++x)
{
ColorRGBA color;
SDL_GetRGBA(CSDL_Ext::getPixel(surf, x, y), surf->format, &color.r, &color.g, &color.b, &color.a);
optimizer.optimizeSurface(surf);
SDL_FreeSurface(surf);
if (color.a != SDL_ALPHA_TRANSPARENT)
{
// opaque
top = std::min(top, y);
left = std::min(left, x);
right = std::max(right, x);
bottom = std::max(bottom, y);
}
}
}
}
if (left == surf->w)
{
// empty image - simply delete it
SDL_FreeSurface(surf);
surf = nullptr;
return;
}
if (left != 0 || top != 0 || right != surf->w - 1 || bottom != surf->h - 1)
{
// non-zero border found
Rect newDimensions(left, top, right - left + 1, bottom - top + 1);
SDL_Rect rectSDL = CSDL_Ext::toSDL(newDimensions);
auto newSurface = CSDL_Ext::newSurface(newDimensions.dimensions(), surf);
SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE);
SDL_BlitSurface(surf, &rectSDL, newSurface, nullptr);
if (SDL_HasColorKey(surf))
{
uint32_t colorKey;
SDL_GetColorKey(surf, &colorKey);
SDL_SetColorKey(newSurface, SDL_TRUE, colorKey);
}
SDL_FreeSurface(surf);
surf = newSurface;
margins.x += left;
margins.y += top;
}
surf = optimizer.acquireResultSurface();
margins = optimizer.getResultDimensions().topLeft();
fullSize = optimizer.getResultDimensions().dimensions();
}
std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode mode) const
@@ -234,22 +164,20 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
SDL_Surface * scaled = nullptr;
SDLImageScaler scaler(surf, Rect(margins, fullSize));
// 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);
scaler.scaleSurfaceIntegerFactor(GH.screenHandler().getScalingFactor(), EScalingAlgorithm::XBRZ_OPAQUE);
else
scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ_ALPHA);
scaler.scaleSurfaceIntegerFactor(GH.screenHandler().getScalingFactor(), EScalingAlgorithm::XBRZ_ALPHA);
SDL_Surface * scaled = scaler.acquireResultSurface();
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);
ret->margins.y = (int) round((float)margins.y * factor);
ret->optimizeSurface();
ret->fullSize = scaler.getResultDimensions().dimensions();
ret->margins = scaler.getResultDimensions().topLeft();
// erase our own reference
SDL_FreeSurface(scaled);
@@ -262,13 +190,14 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL
std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size, SDL_Palette * palette) const
{
float scaleX = static_cast<float>(size.x) / fullSize.x;
float scaleY = static_cast<float>(size.y) / fullSize.y;
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
auto scaled = CSDL_Ext::scaleSurface(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY), EScalingAlgorithm::BILINEAR);
SDLImageScaler scaler(surf, Rect(margins, fullSize));
scaler.scaleSurface(size, EScalingAlgorithm::XBRZ_ALPHA);
auto scaled = scaler.acquireResultSurface();
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]);
@@ -278,12 +207,8 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size,
CSDL_Ext::setDefaultColorKey(scaled);//just in case
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);
ret->margins.x = (int) round((float)margins.x * scaleX);
ret->margins.y = (int) round((float)margins.y * scaleY);
ret->fullSize = scaler.getResultDimensions().dimensions();
ret->margins = scaler.getResultDimensions().topLeft();
// erase our own reference
SDL_FreeSurface(scaled);

View File

@@ -0,0 +1,233 @@
/*
* SDLImageScaler.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 "SDLImageScaler.h"
#include "SDL_Extensions.h"
#include "../CMT.h"
#include "../xBRZ/xbrz.h"
#include <tbb/parallel_for.h>
#include <SDL_surface.h>
SDLImageOptimizer::SDLImageOptimizer(SDL_Surface * surf, const Rect & virtualDimensions)
: surf(surf)
, virtualDimensions(virtualDimensions)
{
}
void SDLImageOptimizer::optimizeSurface(SDL_Surface * formatSourceSurface)
{
if (!surf)
return;
int left = surf->w;
int top = surf->h;
int right = 0;
int bottom = 0;
// locate fully-transparent area around image
// H3 hadles this on format level, but mods or images scaled in runtime do not
if (surf->format->palette)
{
for (int y = 0; y < surf->h; ++y)
{
const uint8_t * row = static_cast<uint8_t *>(surf->pixels) + y * surf->pitch;
for (int x = 0; x < surf->w; ++x)
{
if (row[x] != 0)
{
// opaque or can be opaque (e.g. disabled shadow)
top = std::min(top, y);
left = std::min(left, x);
right = std::max(right, x);
bottom = std::max(bottom, y);
}
}
}
}
else
{
for (int y = 0; y < surf->h; ++y)
{
for (int x = 0; x < surf->w; ++x)
{
ColorRGBA color;
SDL_GetRGBA(CSDL_Ext::getPixel(surf, x, y), surf->format, &color.r, &color.g, &color.b, &color.a);
if (color.a != SDL_ALPHA_TRANSPARENT)
{
// opaque
top = std::min(top, y);
left = std::min(left, x);
right = std::max(right, x);
bottom = std::max(bottom, y);
}
}
}
}
// empty image
if (left == surf->w)
return;
if (left != 0 || top != 0 || right != surf->w - 1 || bottom != surf->h - 1)
{
// non-zero border found
Rect newDimensions(left, top, right - left + 1, bottom - top + 1);
SDL_Rect rectSDL = CSDL_Ext::toSDL(newDimensions);
auto newSurface = CSDL_Ext::newSurface(newDimensions.dimensions(), formatSourceSurface);
SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE);
SDL_BlitSurface(surf, &rectSDL, newSurface, nullptr);
if (SDL_HasColorKey(surf))
{
uint32_t colorKey;
SDL_GetColorKey(surf, &colorKey);
SDL_SetColorKey(newSurface, SDL_TRUE, colorKey);
}
output = newSurface;
virtualDimensions.x += left;
virtualDimensions.y += top;
}
else
{
output = surf;
output->refcount += 1;
}
}
SDL_Surface * SDLImageOptimizer::acquireResultSurface()
{
SDL_Surface * result = output;
output = nullptr;
return result;
}
const Rect & SDLImageOptimizer::getResultDimensions() const
{
return virtualDimensions;
}
void SDLImageScaler::scaleSurface(Point targetDimensions, EScalingAlgorithm algorithm)
{
if(!targetDimensions.x || !targetDimensions.y)
throw std::runtime_error("invalid scaling dimensions!");
Point inputSurfaceSize(intermediate->w, intermediate->h);
Point outputSurfaceSize = targetDimensions * inputSurfaceSize / virtualDimensionsInput.dimensions();
Point outputMargins = targetDimensions * virtualDimensionsInput.topLeft() / virtualDimensionsInput.dimensions();
// TODO: use xBRZ if possible? E.g. when scaling to 150% do 100% -> 200% via xBRZ and then linear downscale 200% -> 150%?
// Need to investigate which is optimal for performance and for visuals
ret = CSDL_Ext::newSurface(Point(outputSurfaceSize.x, outputSurfaceSize.y), intermediate);
virtualDimensionsOutput = Rect(outputMargins, targetDimensions); // TODO: account for input virtual size
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);
}
void SDLImageScaler::scaleSurfaceIntegerFactor(int factor, EScalingAlgorithm algorithm)
{
if(factor == 0)
throw std::runtime_error("invalid scaling factor!");
int newWidth = intermediate->w * factor;
int newHight = intermediate->h * factor;
virtualDimensionsOutput = virtualDimensionsInput * factor;
ret = CSDL_Ext::newSurface(Point(newWidth, newHight), intermediate);
assert(intermediate->pitch == intermediate->w * 4);
assert(ret->pitch == ret->w * 4);
const uint32_t * srcPixels = static_cast<const uint32_t*>(intermediate->pixels);
uint32_t * dstPixels = static_cast<uint32_t*>(ret->pixels);
switch (algorithm)
{
case EScalingAlgorithm::NEAREST:
xbrz::nearestNeighborScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
break;
case EScalingAlgorithm::BILINEAR:
xbrz::bilinearScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
break;
case EScalingAlgorithm::XBRZ_ALPHA:
case EScalingAlgorithm::XBRZ_OPAQUE:
{
auto format = algorithm == EScalingAlgorithm::XBRZ_OPAQUE ? xbrz::ColorFormat::ARGB_CLAMPED : xbrz::ColorFormat::ARGB;
if(intermediate->h < 32)
{
// for tiny images tbb incurs too high overhead
xbrz::scale(factor, srcPixels, dstPixels, intermediate->w, intermediate->h, format, {});
}
else
{
// xbrz recommends granulation of 16, but according to tests, for smaller images granulation of 4 is actually the best option
const int granulation = intermediate->h > 400 ? 16 : 4;
tbb::parallel_for(tbb::blocked_range<size_t>(0, intermediate->h, granulation), [this, factor, srcPixels, dstPixels, format](const tbb::blocked_range<size_t> & r)
{
xbrz::scale(factor, srcPixels, dstPixels, intermediate->w, intermediate->h, format, {}, r.begin(), r.end());
});
}
break;
}
default:
throw std::runtime_error("invalid scaling algorithm!");
}
}
SDLImageScaler::SDLImageScaler(SDL_Surface * surf)
:SDLImageScaler(surf, Rect(0,0,surf->w, surf->h))
{
}
SDLImageScaler::SDLImageScaler(SDL_Surface * surf, const Rect & virtualDimensions)
{
SDLImageOptimizer optimizer(surf, virtualDimensions);
optimizer.optimizeSurface(screen);
intermediate = optimizer.acquireResultSurface();
virtualDimensionsInput = optimizer.getResultDimensions();
if (intermediate == surf)
{
SDL_FreeSurface(intermediate);
intermediate = SDL_ConvertSurfaceFormat(surf, SDL_PIXELFORMAT_ARGB8888, 0);
}
}
SDLImageScaler::~SDLImageScaler()
{
SDL_FreeSurface(intermediate);
SDL_FreeSurface(ret);
}
SDL_Surface * SDLImageScaler::acquireResultSurface()
{
SDL_Surface * result = ret;
ret = nullptr;
return result;
}
const Rect & SDLImageScaler::getResultDimensions() const
{
return virtualDimensionsOutput;
}

View File

@@ -0,0 +1,63 @@
/*
* SDLImageScaler.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 "../../lib/Rect.h"
class SDLImageOptimizer : boost::noncopyable
{
SDL_Surface * surf = nullptr;
SDL_Surface * output = nullptr;
Rect virtualDimensions = Rect(0,0,0,0);
public:
SDLImageOptimizer(SDL_Surface * surf, const Rect & virtualDimensions);
void optimizeSurface(SDL_Surface * formatSourceSurface);
/// Aquires resulting surface and transfers surface ownership to the caller
/// May return nullptr if input image was empty
SDL_Surface * acquireResultSurface();
/// Returns adjusted virtual dimensions of resulting surface
const Rect & getResultDimensions() const;
};
/// Class that performs scaling of SDL surfaces
/// Object construction MUST be performed while holding UI lock
/// but task execution can be performed asynchronously if needed
class SDLImageScaler : boost::noncopyable
{
SDL_Surface * intermediate = nullptr;
SDL_Surface * ret = nullptr;
Rect virtualDimensionsInput = Rect(0,0,0,0);
Rect virtualDimensionsOutput = Rect(0,0,0,0);
public:
SDLImageScaler(SDL_Surface * surf);
SDLImageScaler(SDL_Surface * surf, const Rect & virtualDimensions);
~SDLImageScaler();
/// Performs upscaling or downscaling to a requested dimensions
/// Aspect ratio is NOT maintained.
/// xbrz algorithm is not supported in this mode
void scaleSurface(Point dimensions, EScalingAlgorithm algorithm);
/// Performs upscaling by specified integral factor, potentially using xbrz algorithm if requested
void scaleSurfaceIntegerFactor(int factor, EScalingAlgorithm algorithm);
/// Aquires resulting surface and transfers surface ownership to the caller
/// May return nullptr if input image was empty
SDL_Surface * acquireResultSurface();
/// Returns adjusted virtual dimensions of resulting surface
const Rect & getResultDimensions() const;
};

View File

@@ -631,89 +631,6 @@ 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, EScalingAlgorithm algorithm)
{
if(!surf || !width || !height)
return nullptr;
// TODO: use xBRZ if possible? E.g. when scaling to 150% do 100% -> 200% via xBRZ and then linear downscale 200% -> 150%?
// Need to investigate which is optimal for performance and for visuals
SDL_Surface * intermediate = SDL_ConvertSurface(surf, screen->format, 0);
SDL_Surface * ret = newSurface(Point(width, height), intermediate);
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;
}
SDL_Surface * CSDL_Ext::scaleSurfaceIntegerFactor(SDL_Surface * surf, int factor, EScalingAlgorithm algorithm)
{
if(surf == nullptr || factor == 0)
return nullptr;
int newWidth = surf->w * factor;
int newHight = surf->h * factor;
SDL_Surface * intermediate = SDL_ConvertSurfaceFormat(surf, SDL_PIXELFORMAT_ARGB8888, 0);
SDL_Surface * ret = newSurface(Point(newWidth, newHight), intermediate);
assert(intermediate->pitch == intermediate->w * 4);
assert(ret->pitch == ret->w * 4);
const uint32_t * srcPixels = static_cast<const uint32_t*>(intermediate->pixels);
uint32_t * dstPixels = static_cast<uint32_t*>(ret->pixels);
switch (algorithm)
{
case EScalingAlgorithm::NEAREST:
xbrz::nearestNeighborScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
break;
case EScalingAlgorithm::BILINEAR:
xbrz::bilinearScale(srcPixels, intermediate->w, intermediate->h, dstPixels, ret->w, ret->h);
break;
case EScalingAlgorithm::XBRZ_ALPHA:
case EScalingAlgorithm::XBRZ_OPAQUE:
{
auto format = algorithm == EScalingAlgorithm::XBRZ_OPAQUE ? xbrz::ColorFormat::ARGB_CLAMPED : xbrz::ColorFormat::ARGB;
if(intermediate->h < 32)
{
// for tiny images tbb incurs too high overhead
xbrz::scale(factor, srcPixels, dstPixels, intermediate->w, intermediate->h, format, {});
}
else
{
// xbrz recommends granulation of 16, but according to tests, for smaller images granulation of 4 is actually the best option
const int granulation = intermediate->h > 400 ? 16 : 4;
tbb::parallel_for(tbb::blocked_range<size_t>(0, intermediate->h, granulation), [factor, srcPixels, dstPixels, intermediate, format](const tbb::blocked_range<size_t> & r)
{
xbrz::scale(factor, srcPixels, dstPixels, intermediate->w, intermediate->h, format, {}, r.begin(), r.end());
});
}
break;
}
default:
throw std::runtime_error("invalid scaling algorithm!");
}
SDL_FreeSurface(intermediate);
return ret;
}
void CSDL_Ext::blitSurface(SDL_Surface * src, const Rect & srcRectInput, SDL_Surface * dst, const Point & dstPoint)
{
SDL_Rect srcRect = CSDL_Ext::toSDL(srcRectInput);

View File

@@ -18,7 +18,6 @@ struct SDL_Renderer;
struct SDL_Texture;
struct SDL_Surface;
struct SDL_Color;
enum class EScalingAlgorithm : int8_t;
VCMI_LIB_NAMESPACE_BEGIN
@@ -91,10 +90,6 @@ using TColorPutterAlpha = void (*)(uint8_t *&, const uint8_t &, const uint8_t &,
template<int bpp>
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, EScalingAlgorithm scaler);
SDL_Surface * scaleSurfaceIntegerFactor(SDL_Surface * surf, int factor, EScalingAlgorithm scaler);
template<int bpp>
void convertToGrayscaleBpp(SDL_Surface * surf, const Rect & rect);
void convertToGrayscale(SDL_Surface * surf, const Rect & rect);

View File

@@ -260,7 +260,7 @@ void ScalableImageShared::draw(SDL_Surface * where, const Point & dest, const Re
if (scaled.at(scalingFactor).shadow.at(0))
flipAndDraw(scaled.at(scalingFactor).shadow, Colors::WHITE_TRUE, parameters.alphaValue);
if (parameters.player != PlayerColor::CANNOT_DETERMINE)
if (parameters.player.isValidPlayer())
{
scaled.at(scalingFactor).playerColored[parameters.player.getNum()]->draw(where, parameters.palette, dest, src, Colors::WHITE_TRUE, parameters.alphaValue, locator.layer);
}
@@ -351,7 +351,7 @@ void ScalableImageInstance::playerColored(const PlayerColor & player)
{
parameters.player = player;
if (!parameters.palette)
if (parameters.palette)
parameters.playerColored(player);
image->preparePlayerColoredImage(player);

View File

@@ -15,9 +15,6 @@
#include "../../lib/Color.h"
#include <tbb/concurrent_queue.h>
#include <tbb/task_arena.h>
struct SDL_Palette;
class ScalableImageInstance;
@@ -47,24 +44,6 @@ struct ScalableImageParameters : boost::noncopyable
void adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask);
};
class ImageScaler
{
ImageScaler();
tbb::task_arena arena;
public:
static ImageScaler & getInstance()
{
static ImageScaler scaler;
return scaler;
}
void enqueueTask(const std::function<void()> & task)
{
arena.enqueue(task);
}
};
class ScalableImageShared final : public std::enable_shared_from_this<ScalableImageShared>, boost::noncopyable
{
static constexpr int scalingSize = 5; // 0-4 range. TODO: switch to either 2-4 or 1-4
@@ -97,12 +76,6 @@ class ScalableImageShared final : public std::enable_shared_from_this<ScalableIm
/// Locator of this image, for loading additional (e.g. upscaled) images
const SharedImageLocator locator;
/// Contains all upscaling tasks related to this image that finished processing and can be applied
tbb::concurrent_queue<std::function<void()>> upscalingQueue;
/// Number of images that are currently being upscaled
int scheduledUpscalingEvents = 0;
std::shared_ptr<const ISharedImage> loadOrGenerateImage(EImageBlitMode mode, int8_t scalingFactor, PlayerColor color) const;
void loadScaledImages(int8_t scalingFactor, PlayerColor color);

View File

@@ -54,6 +54,11 @@ public:
return Point(x*mul, y*mul);
}
constexpr Point operator/(const Point &b) const
{
return Point(x/b.x,y/b.y);
}
constexpr Point operator*(const Point &b) const
{
return Point(x*b.x,y*b.y);

View File

@@ -120,7 +120,7 @@ TurnInfo::TurnInfo(TurnInfoCache * sharedCache, const CGHeroInstance * target, i
{
static const CSelector selector = Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT);
const auto & bonuses = sharedCache->roughTerrainDiscount.getBonusList(target, selector);
roughTerrainDiscountValue = bonuses->getFirst(daySelector) != nullptr;
roughTerrainDiscountValue = bonuses->valOfBonuses(daySelector);
}
{