From def1e3583636fbf5c67b9289eca74f31a1466fe6 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 20 Feb 2023 18:37:33 +0200 Subject: [PATCH] Use SDL BlitMode's to speed up image rendering --- Global.h | 13 ++++---- client/adventureMap/MapRenderer.cpp | 1 + client/adventureMap/MapRendererContext.h | 4 +-- client/adventureMap/MapView.cpp | 10 +++--- client/adventureMap/MapView.h | 2 +- client/adventureMap/mapHandler.h | 40 +++++++++++++----------- client/render/CAnimation.cpp | 4 +-- client/render/IImage.h | 15 +++++++++ client/renderSDL/SDLImage.cpp | 37 ++++++++++++++++------ client/renderSDL/SDLImage.h | 9 ++++-- client/windows/CCastleInterface.cpp | 8 ++--- 11 files changed, 91 insertions(+), 52 deletions(-) diff --git a/Global.h b/Global.h index 2ee5cd2c5..28ed3ffe6 100644 --- a/Global.h +++ b/Global.h @@ -116,33 +116,32 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size."); #define _USE_MATH_DEFINES -#include -#include - #include #include +#include +#include #include #include #include #include -#include +#include #include +#include #include #include #include #include +#include #include #include #include #include #include #include -#include #include +#include #include #include -#include -#include //The only available version is 3, as of Boost 1.50 #include diff --git a/client/adventureMap/MapRenderer.cpp b/client/adventureMap/MapRenderer.cpp index 708f94307..c269a69b8 100644 --- a/client/adventureMap/MapRenderer.cpp +++ b/client/adventureMap/MapRenderer.cpp @@ -162,6 +162,7 @@ void MapRendererTerrain::renderTile(const IMapRendererContext & context, Canvas image->shiftPalette(242, 14, context.terrainImageIndex(14)); } + image->setBlitMode(EImageBlitMode::OPAQUE); target.draw(image, Point(0, 0)); } diff --git a/client/adventureMap/MapRendererContext.h b/client/adventureMap/MapRendererContext.h index 32554a177..ae1920877 100644 --- a/client/adventureMap/MapRendererContext.h +++ b/client/adventureMap/MapRendererContext.h @@ -64,8 +64,8 @@ public: /// returns animation frame for terrain virtual size_t terrainImageIndex(size_t groupSize) const = 0; - /// returns size of ouput tile, in pixels. 32x32 for "standard" map, may be smaller for world view mode - virtual Point getTileSize() const = 0; +// /// returns size of ouput tile, in pixels. 32x32 for "standard" map, may be smaller for world view mode +// virtual Point getTileSize() const = 0; /// if true, map grid should be visible on map virtual bool showGrid() const = 0; diff --git a/client/adventureMap/MapView.cpp b/client/adventureMap/MapView.cpp index 41d892e74..94ee85ec8 100644 --- a/client/adventureMap/MapView.cpp +++ b/client/adventureMap/MapView.cpp @@ -189,14 +189,14 @@ size_t MapRendererContext::terrainImageIndex(size_t groupSize) const return frameIndex; } -Point MapRendererContext::getTileSize() const -{ - return Point(32, 32); -} +//Point MapRendererContext::getTileSize() const +//{ +// return Point(32, 32); +//} bool MapRendererContext::showGrid() const { - return true; // settings["gameTweaks"]["showGrid"].Bool(); + return settings["gameTweaks"]["showGrid"].Bool(); } bool MapRendererContext::showVisitable() const diff --git a/client/adventureMap/MapView.h b/client/adventureMap/MapView.h index 39ad45f1b..c3071250c 100644 --- a/client/adventureMap/MapView.h +++ b/client/adventureMap/MapView.h @@ -68,7 +68,7 @@ public: double objectTransparency(ObjectInstanceID objectID) const override; size_t objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const override; size_t terrainImageIndex(size_t groupSize) const override; - Point getTileSize() const override; +// Point getTileSize() const override; bool showGrid() const override; bool showVisitable() const override; bool showBlockable() const override; diff --git a/client/adventureMap/mapHandler.h b/client/adventureMap/mapHandler.h index 956ffef2c..61aad811f 100644 --- a/client/adventureMap/mapHandler.h +++ b/client/adventureMap/mapHandler.h @@ -41,27 +41,31 @@ class IImage; class CMapHandler; class IMapObjectObserver; +// from VwSymbol.def enum class EWorldViewIcon { TOWN = 0, - HERO, - ARTIFACT, - TELEPORT, - GATE, - MINE_WOOD, - MINE_MERCURY, - MINE_STONE, - MINE_SULFUR, - MINE_CRYSTAL, - MINE_GEM, - MINE_GOLD, - RES_WOOD, - RES_MERCURY, - RES_STONE, - RES_SULFUR, - RES_CRYSTAL, - RES_GEM, - RES_GOLD, + HERO = 1, + ARTIFACT = 2, + TELEPORT = 3, + GATE = 4, + MINE_WOOD = 5, + MINE_MERCURY = 6, + MINE_STONE = 7, + MINE_SULFUR = 8, + MINE_CRYSTAL = 9, + MINE_GEM = 10, + MINE_GOLD = 11, + RES_WOOD = 12, + RES_MERCURY = 13, + RES_STONE = 14, + RES_SULFUR = 15, + RES_CRYSTAL = 16, + RES_GEM = 17, + RES_GOLD = 18, + + ICONS_PER_PLAYER = 19, + ICONS_TOTAL = 19 * 9 // 8 players + neutral set at the end }; class CMapHandler diff --git a/client/render/CAnimation.cpp b/client/render/CAnimation.cpp index 2f884fdff..19fe67dfe 100644 --- a/client/render/CAnimation.cpp +++ b/client/render/CAnimation.cpp @@ -69,13 +69,13 @@ bool CAnimation::loadFrame(size_t frame, size_t group) // still here? image is missing printError(frame, group, "LoadFrame"); - images[group][frame] = std::make_shared("DEFAULT"); + images[group][frame] = std::make_shared("DEFAULT", EImageBlitMode::ALPHA); } else //load from separate file { auto img = getFromExtraDef(source[group][frame]["file"].String()); if(!img) - img = std::make_shared(source[group][frame]); + img = std::make_shared(source[group][frame], EImageBlitMode::ALPHA); images[group][frame] = img; return true; diff --git a/client/render/IImage.h b/client/render/IImage.h index 63eb65b62..0facf0ee9 100644 --- a/client/render/IImage.h +++ b/client/render/IImage.h @@ -21,6 +21,19 @@ struct SDL_Surface; struct SDL_Color; class ColorFilter; +/// Defines which blit method will be selected when image is used for rendering +enum class EImageBlitMode : uint8_t +{ + /// Image can have no transparency and can be only used as background + OPAQUE, + + /// Image can have only a single color as transparency and has no semi-transparent areas + COLORKEY, + + /// Image might have full alpha transparency range, e.g. shadows + ALPHA +}; + /* * Base class for images, can be used for non-animation pictures as well */ @@ -57,6 +70,7 @@ public: virtual void resetPalette() = 0; virtual void setAlpha(uint8_t value) = 0; + virtual void setBlitMode(EImageBlitMode mode) = 0; //only indexed bitmaps with 7 special colors virtual void setSpecialPallete(const SpecialPalette & SpecialPalette) = 0; @@ -69,6 +83,7 @@ public: /// loads image from specified file. Returns 0-sized images on failure static std::shared_ptr createFromFile( const std::string & path ); + static std::shared_ptr createFromFile( const std::string & path, EImageBlitMode mode ); /// temporary compatibility method. Creates IImage from existing SDL_Surface /// Surface will be shared, called must still free it with SDL_FreeSurface diff --git a/client/renderSDL/SDLImage.cpp b/client/renderSDL/SDLImage.cpp index 2a2e37dcf..00a7a3bee 100644 --- a/client/renderSDL/SDLImage.cpp +++ b/client/renderSDL/SDLImage.cpp @@ -26,12 +26,12 @@ class SDLImageLoader; std::shared_ptr IImage::createFromFile( const std::string & path ) { - return std::shared_ptr(new SDLImage(path)); + return std::shared_ptr(new SDLImage(path, EImageBlitMode::ALPHA)); } std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) { - return std::shared_ptr(new SDLImage(source, true)); + return std::shared_ptr(new SDLImage(source, EImageBlitMode::ALPHA)); } IImage::IImage() = default; @@ -57,9 +57,10 @@ SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group) data->loadFrame(frame, group, loader); savePalette(); + setBlitMode(EImageBlitMode::ALPHA); } -SDLImage::SDLImage(SDL_Surface * from, bool extraRef) +SDLImage::SDLImage(SDL_Surface * from, EImageBlitMode mode) : surf(nullptr), margins(0, 0), fullSize(0, 0), @@ -70,14 +71,14 @@ SDLImage::SDLImage(SDL_Surface * from, bool extraRef) return; savePalette(); + setBlitMode(mode); - if (extraRef) - surf->refcount++; + surf->refcount++; fullSize.x = surf->w; fullSize.y = surf->h; } -SDLImage::SDLImage(const JsonNode & conf) +SDLImage::SDLImage(const JsonNode & conf, EImageBlitMode mode) : surf(nullptr), margins(0, 0), fullSize(0, 0), @@ -91,6 +92,7 @@ SDLImage::SDLImage(const JsonNode & conf) return; savePalette(); + setBlitMode(mode); const JsonNode & jsonMargins = conf["margins"]; @@ -111,7 +113,7 @@ SDLImage::SDLImage(const JsonNode & conf) } } -SDLImage::SDLImage(std::string filename) +SDLImage::SDLImage(std::string filename, EImageBlitMode mode) : surf(nullptr), margins(0, 0), fullSize(0, 0), @@ -127,6 +129,7 @@ SDLImage::SDLImage(std::string filename) else { savePalette(); + setBlitMode(mode); fullSize.x = surf->w; fullSize.y = surf->h; } @@ -172,7 +175,7 @@ void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) cons if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0) logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError()); - if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE) + if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE && blitMode == EImageBlitMode::ALPHA) { CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift); } @@ -196,7 +199,7 @@ std::shared_ptr SDLImage::scaleFast(const Point & size) const else CSDL_Ext::setDefaultColorKey(scaled);//just in case - SDLImage * ret = new SDLImage(scaled, false); + SDLImage * ret = new SDLImage(scaled, EImageBlitMode::ALPHA); ret->fullSize.x = (int) round((float)fullSize.x * scaleX); ret->fullSize.y = (int) round((float)fullSize.y * scaleY); @@ -204,6 +207,9 @@ std::shared_ptr SDLImage::scaleFast(const Point & size) const ret->margins.x = (int) round((float)margins.x * scaleX); ret->margins.y = (int) round((float)margins.y * scaleY); + // erase our own reference + SDL_FreeSurface(scaled); + return std::shared_ptr(ret); } @@ -220,7 +226,18 @@ void SDLImage::playerColored(PlayerColor player) void SDLImage::setAlpha(uint8_t value) { CSDL_Ext::setAlpha (surf, value); - SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); + if (value != 255) + SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); +} + +void SDLImage::setBlitMode(EImageBlitMode mode) +{ + blitMode = mode; + + if (blitMode != EImageBlitMode::OPAQUE && surf->format->Amask != 0) + SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); + else + SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE); } void SDLImage::setFlagColor(PlayerColor player) diff --git a/client/renderSDL/SDLImage.h b/client/renderSDL/SDLImage.h index 6d719f17c..437daceab 100644 --- a/client/renderSDL/SDLImage.h +++ b/client/renderSDL/SDLImage.h @@ -37,15 +37,17 @@ public: //total size including borders Point fullSize; + EImageBlitMode blitMode; + public: //Load image from def file SDLImage(CDefFile *data, size_t frame, size_t group=0); //Load from bitmap file - SDLImage(std::string filename); + SDLImage(std::string filename, EImageBlitMode blitMode); - SDLImage(const JsonNode & conf); + SDLImage(const JsonNode & conf, EImageBlitMode blitMode); //Create using existing surface, extraRef will increase refcount on SDL_Surface - SDLImage(SDL_Surface * from, bool extraRef); + SDLImage(SDL_Surface * from, EImageBlitMode blitMode); ~SDLImage(); // Keep the original palette, in order to do color switching operation @@ -69,6 +71,7 @@ public: void resetPalette() override; void setAlpha(uint8_t value) override; + void setBlitMode(EImageBlitMode mode) override; void setSpecialPallete(const SpecialPalette & SpecialPalette) override; diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 1c3d184d6..b8e58e0a1 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -61,6 +61,8 @@ CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town parent(Par), town(Town), str(Str), + border(nullptr), + area(nullptr), stateTimeCounter(BUILD_ANIMATION_FINISHED_TIMEPOINT) { addUsedEvents(LCLICK | RCLICK | HOVER); @@ -83,13 +85,9 @@ CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town if(!str->borderName.empty()) border = IImage::createFromFile(str->borderName); - else - border = nullptr; if(!str->areaName.empty()) area = IImage::createFromFile(str->areaName); - else - area = nullptr; } const CBuilding * CBuildingRect::getBuilding() @@ -565,6 +563,8 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town): OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); background = std::make_shared(town->town->clientInfo.townBackground); + background->needRefresh = true; + background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE); pos.w = background->pos.w; pos.h = background->pos.h;