1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-08 00:39:47 +02:00

More robust management of body/shadow/overlay split

This commit is contained in:
Ivan Savenko 2024-11-17 17:54:55 +00:00
parent c82db9d574
commit 251155d913
19 changed files with 163 additions and 176 deletions

View File

@ -394,7 +394,7 @@ void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBu
{
std::string URI;
singleWordBuffer >> URI;
auto anim = GH.renderHandler().loadAnimation(AnimationPath::builtin(URI), EImageBlitMode::ALPHA);
auto anim = GH.renderHandler().loadAnimation(AnimationPath::builtin(URI), EImageBlitMode::SIMPLE);
anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
}

View File

@ -883,7 +883,7 @@ uint32_t CastAnimation::getAttackClimaxFrame() const
EffectAnimation::EffectAnimation(BattleInterface & owner, const AnimationPath & animationName, int effects, bool reversed):
BattleAnimation(owner),
animation(GH.renderHandler().loadAnimation(animationName, EImageBlitMode::ALPHA)),
animation(GH.renderHandler().loadAnimation(animationName, EImageBlitMode::SIMPLE)),
effectFlags(effects),
effectFinished(false),
reversed(reversed)

View File

@ -114,7 +114,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
//preparing cells and hexes
cellBorder = GH.renderHandler().loadImage(ImagePath::builtin("CCELLGRD.BMP"), EImageBlitMode::COLORKEY);
cellShade = GH.renderHandler().loadImage(ImagePath::builtin("CCELLSHD.BMP"), EImageBlitMode::ALPHA);
cellShade = GH.renderHandler().loadImage(ImagePath::builtin("CCELLSHD.BMP"), EImageBlitMode::SIMPLE);
cellUnitMovementHighlight = GH.renderHandler().loadImage(ImagePath::builtin("UnitMovementHighlight.PNG"), EImageBlitMode::COLORKEY);
cellUnitMaxMovementHighlight = GH.renderHandler().loadImage(ImagePath::builtin("UnitMaxMovementHighlight.PNG"), EImageBlitMode::COLORKEY);
@ -124,8 +124,6 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
rangedFullDamageLimitImages = GH.renderHandler().loadAnimation(AnimationPath::builtin("battle/rangeHighlights/rangeHighlightsGreen.json"), EImageBlitMode::COLORKEY);
shootingRangeLimitImages = GH.renderHandler().loadAnimation(AnimationPath::builtin("battle/rangeHighlights/rangeHighlightsRed.json"), EImageBlitMode::COLORKEY);
cellShade->setShadowEnabled(true);
if(!owner.siegeController)
{
auto bfieldType = owner.getBattle()->battleGetBattlefieldType();

View File

@ -398,7 +398,7 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
else
animationPath = hero->getHeroClass()->imageBattleMale;
animation = GH.renderHandler().loadAnimation(animationPath, EImageBlitMode::ALPHA);
animation = GH.renderHandler().loadAnimation(animationPath, EImageBlitMode::WITH_SHADOW);
pos.w = 64;
pos.h = 136;

View File

@ -50,11 +50,11 @@ void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
if (oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
{
// obstacle uses single bitmap image for animations
obstacleImages[oi.uniqueID] = GH.renderHandler().loadImage(animationName.toType<EResType::IMAGE>(), EImageBlitMode::COLORKEY);
obstacleImages[oi.uniqueID] = GH.renderHandler().loadImage(animationName.toType<EResType::IMAGE>(), EImageBlitMode::SIMPLE);
}
else
{
obstacleAnimations[oi.uniqueID] = GH.renderHandler().loadAnimation(animationName, EImageBlitMode::COLORKEY);
obstacleAnimations[oi.uniqueID] = GH.renderHandler().loadAnimation(animationName, EImageBlitMode::SIMPLE);
obstacleImages[oi.uniqueID] = obstacleAnimations[oi.uniqueID]->getImage(0);
}
}
@ -78,7 +78,7 @@ void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges
if(animationPath.empty())
continue;
auto animation = GH.renderHandler().loadAnimation(animationPath, EImageBlitMode::COLORKEY);
auto animation = GH.renderHandler().loadAnimation(animationPath, EImageBlitMode::SIMPLE);
auto first = animation->getImage(0, 0);
if(!first)
continue;
@ -105,7 +105,7 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
if(!oi->visibleForSide(side, owner.getBattle()->battleHasNativeStack(side)))
continue;
auto animation = GH.renderHandler().loadAnimation(oi->getAppearAnimation(), EImageBlitMode::ALPHA);
auto animation = GH.renderHandler().loadAnimation(oi->getAppearAnimation(), EImageBlitMode::SIMPLE);
auto first = animation->getImage(0, 0);
if(!first)
continue;

View File

@ -17,6 +17,7 @@
#include "../render/CAnimation.h"
#include "../render/Canvas.h"
#include "../render/ColorFilter.h"
#include "../render/Colors.h"
#include "../render/IRenderHandler.h"
static const ColorRGBA creatureBlueBorder = { 0, 255, 255, 255 };
@ -199,8 +200,8 @@ CreatureAnimation::CreatureAnimation(const AnimationPath & name_, TSpeedControll
speedController(controller),
once(false)
{
forward = GH.renderHandler().loadAnimation(name_, EImageBlitMode::ALPHA);
reverse = GH.renderHandler().loadAnimation(name_, EImageBlitMode::ALPHA);
forward = GH.renderHandler().loadAnimation(name_, EImageBlitMode::WITH_SHADOW_AND_OVERLAY);
reverse = GH.renderHandler().loadAnimation(name_, EImageBlitMode::WITH_SHADOW_AND_OVERLAY);
// if necessary, add one frame into vcmi-only group DEAD
if(forward->size(size_t(ECreatureAnimType::DEAD)) == 0)
@ -339,15 +340,14 @@ void CreatureAnimation::nextFrame(Canvas & canvas, const ColorFilter & shifter,
if(image)
{
image->setShadowEnabled(true);
image->setOverlayEnabled(isIdle());
if (isIdle())
image->setOverlayColor(genBorderColor(getBorderStrength(elapsedTime), border));
else
image->setOverlayColor(Colors::TRANSPARENCY);
image->adjustPalette(shifter, 0);
canvas.draw(image, pos.topLeft(), Rect(0, 0, pos.w, pos.h));
}
}

View File

@ -316,7 +316,7 @@ uint8_t MapRendererBorder::checksum(IMapRendererContext & context, const int3 &
MapRendererFow::MapRendererFow()
{
fogOfWarFullHide = GH.renderHandler().loadAnimation(AnimationPath::builtin("TSHRC"), EImageBlitMode::OPAQUE);
fogOfWarPartialHide = GH.renderHandler().loadAnimation(AnimationPath::builtin("TSHRE"), EImageBlitMode::ALPHA);
fogOfWarPartialHide = GH.renderHandler().loadAnimation(AnimationPath::builtin("TSHRE"), EImageBlitMode::SIMPLE);
static const std::vector<int> rotations = {22, 15, 2, 13, 12, 16, 28, 17, 20, 19, 7, 24, 26, 25, 30, 32, 27};
@ -383,24 +383,25 @@ std::shared_ptr<CAnimation> MapRendererObjects::getBaseAnimation(const CGObjectI
}
bool generateMovementGroups = (info->id == Obj::BOAT) || (info->id == Obj::HERO);
bool enableOverlay = obj->ID != Obj::BOAT && obj->ID != Obj::HERO && obj->getOwner() != PlayerColor::UNFLAGGABLE;
// Boat appearance files only contain single, unanimated image
// proper boat animations are actually in different file
if (info->id == Obj::BOAT)
if(auto boat = dynamic_cast<const CGBoat*>(obj); boat && !boat->actualAnimation.empty())
return getAnimation(boat->actualAnimation, generateMovementGroups);
return getAnimation(boat->actualAnimation, generateMovementGroups, enableOverlay);
return getAnimation(info->animationFile, generateMovementGroups);
return getAnimation(info->animationFile, generateMovementGroups, enableOverlay);
}
std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const AnimationPath & filename, bool generateMovementGroups)
std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const AnimationPath & filename, bool generateMovementGroups, bool enableOverlay)
{
auto it = animations.find(filename);
if(it != animations.end())
return it->second;
auto ret = GH.renderHandler().loadAnimation(filename, EImageBlitMode::ALPHA);
auto ret = GH.renderHandler().loadAnimation(filename, enableOverlay ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::WITH_SHADOW);
animations[filename] = ret;
if(generateMovementGroups)
@ -427,14 +428,14 @@ std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectI
{
assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
assert(obj->tempOwner.isValidPlayer());
return getAnimation(AnimationPath::builtin(heroFlags[obj->tempOwner.getNum()]), true);
return getAnimation(AnimationPath::builtin(heroFlags[obj->tempOwner.getNum()]), true, false);
}
if(obj->ID == Obj::BOAT)
{
const auto * boat = dynamic_cast<const CGBoat *>(obj);
if(boat && boat->hero && !boat->flagAnimations[boat->hero->tempOwner.getNum()].empty())
return getAnimation(boat->flagAnimations[boat->hero->tempOwner.getNum()], true);
return getAnimation(boat->flagAnimations[boat->hero->tempOwner.getNum()], true, false);
}
return nullptr;
@ -447,7 +448,7 @@ std::shared_ptr<CAnimation> MapRendererObjects::getOverlayAnimation(const CGObje
// Boats have additional animation with waves around boat
const auto * boat = dynamic_cast<const CGBoat *>(obj);
if(boat && boat->hero && !boat->overlayAnimation.empty())
return getAnimation(boat->overlayAnimation, true);
return getAnimation(boat->overlayAnimation, true, false);
}
return nullptr;
}
@ -478,22 +479,14 @@ void MapRendererObjects::renderImage(IMapRendererContext & context, Canvas & tar
return;
image->setAlpha(transparency);
image->setShadowEnabled(true);
if (object->ID != Obj::HERO)
if (object->ID != Obj::HERO) // heroes use separate image with flag instead of player-colored palette
{
image->setOverlayEnabled(object->getOwner().isValidPlayer() || object->getOwner() == PlayerColor::NEUTRAL);
if (object->getOwner().isValidPlayer())
image->setOverlayColor(graphics->playerColors[object->getOwner().getNum()]);
if (object->getOwner() == PlayerColor::NEUTRAL)
image->setOverlayColor(graphics->neutralColor);
}
else
{
// heroes use separate image with flag instead of player-colored palette
image->setOverlayEnabled(false);
}
Point offsetPixels = context.objectImageOffset(object->id, coordinates);
@ -567,10 +560,10 @@ uint8_t MapRendererObjects::checksum(IMapRendererContext & context, const int3 &
}
MapRendererOverlay::MapRendererOverlay()
: imageGrid(GH.renderHandler().loadImage(ImagePath::builtin("debug/grid"), EImageBlitMode::ALPHA))
, imageBlocked(GH.renderHandler().loadImage(ImagePath::builtin("debug/blocked"), EImageBlitMode::ALPHA))
, imageVisitable(GH.renderHandler().loadImage(ImagePath::builtin("debug/visitable"), EImageBlitMode::ALPHA))
, imageSpellRange(GH.renderHandler().loadImage(ImagePath::builtin("debug/spellRange"), EImageBlitMode::ALPHA))
: imageGrid(GH.renderHandler().loadImage(ImagePath::builtin("debug/grid"), EImageBlitMode::COLORKEY))
, imageBlocked(GH.renderHandler().loadImage(ImagePath::builtin("debug/blocked"), EImageBlitMode::COLORKEY))
, imageVisitable(GH.renderHandler().loadImage(ImagePath::builtin("debug/visitable"), EImageBlitMode::COLORKEY))
, imageSpellRange(GH.renderHandler().loadImage(ImagePath::builtin("debug/spellRange"), EImageBlitMode::COLORKEY))
{
}
@ -626,7 +619,7 @@ uint8_t MapRendererOverlay::checksum(IMapRendererContext & context, const int3 &
}
MapRendererPath::MapRendererPath()
: pathNodes(GH.renderHandler().loadAnimation(AnimationPath::builtin("ADAG"), EImageBlitMode::ALPHA))
: pathNodes(GH.renderHandler().loadAnimation(AnimationPath::builtin("ADAG"), EImageBlitMode::SIMPLE))
{
}

View File

@ -77,7 +77,7 @@ class MapRendererObjects
std::shared_ptr<CAnimation> getFlagAnimation(const CGObjectInstance * obj);
std::shared_ptr<CAnimation> getOverlayAnimation(const CGObjectInstance * obj);
std::shared_ptr<CAnimation> getAnimation(const AnimationPath & filename, bool generateMovementGroups);
std::shared_ptr<CAnimation> getAnimation(const AnimationPath & filename, bool generateMovementGroups, bool enableOverlay);
std::shared_ptr<IImage> getImage(IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr<CAnimation> & animation) const;

View File

@ -37,9 +37,29 @@ enum class EImageBlitMode : uint8_t
/// RGBA: full alpha transparency range, e.g. shadows
COLORKEY,
/// Should be avoided if possible, use only for images that use def's with semi-transparency
/// Indexed or RGBA: Image might have full alpha transparency range, e.g. shadows
ALPHA
/// Full transparency including shadow, but treated as a single image
/// Indexed: Image can have alpha transparency, e.g. shadow
/// RGBA: full alpha transparency range, e.g. shadows
/// Upscaled form: single image, no option to display shadow separately
SIMPLE,
/// RGBA, may consist from 2 separate parts: base and shadow, overlay not preset or treated as part of body
WITH_SHADOW,
/// RGBA, may consist from 3 separate parts: base, shadow, and overlay
WITH_SHADOW_AND_OVERLAY,
/// RGBA, contains only body, with shadow and overlay disabled
ONLY_BODY,
/// RGBA, contains only body, with shadow disabled and overlay treated as part of body
ONLY_BODY_IGNORE_OVERLAY,
/// RGBA, contains only shadow
ONLY_SHADOW,
/// RGBA, contains only overlay
ONLY_OVERLAY,
};
/// Base class for images for use in client code.
@ -75,9 +95,6 @@ public:
//only indexed bitmaps with 7 special colors
virtual void setOverlayColor(const ColorRGBA & color) = 0;
virtual void setShadowEnabled(bool on) = 0;
virtual void setBodyEnabled(bool on) = 0;
virtual void setOverlayEnabled(bool on) = 0;
virtual std::shared_ptr<const ISharedImage> getSharedImage() const = 0;
virtual ~IImage() = default;

View File

@ -124,8 +124,12 @@ std::string ImageLocator::toString() const
if (playerColored.isValidPlayer())
result += "-player" + playerColored.toString();
if (layer != EImageLayer::ALL)
result += "-layer" + std::to_string(static_cast<int>(layer));
if (layer == EImageBlitMode::ONLY_OVERLAY)
result += "-overlay";
if (layer == EImageBlitMode::ONLY_SHADOW)
result += "-shadow";
return result;
}

View File

@ -9,18 +9,11 @@
*/
#pragma once
#include "IImage.h"
#include "../../lib/filesystem/ResourcePath.h"
#include "../../lib/constants/EntityIdentifiers.h"
enum class EImageLayer
{
ALL,
BODY,
SHADOW,
OVERLAY,
};
struct ImageLocator
{
std::optional<ImagePath> image;
@ -28,13 +21,13 @@ struct ImageLocator
int defFrame = -1;
int defGroup = -1;
PlayerColor playerColored = PlayerColor::CANNOT_DETERMINE;
PlayerColor playerColored = PlayerColor::CANNOT_DETERMINE; // FIXME: treat as identical to blue to avoid double-loading?
bool verticalFlip = false;
bool horizontalFlip = false;
int8_t scalingFactor = 0; // 0 = auto / use default scaling
int8_t preScaledFactor = 1;
EImageLayer layer = EImageLayer::ALL;
EImageBlitMode layer = EImageBlitMode::OPAQUE;
ImageLocator() = default;
ImageLocator(const AnimationPath & path, int frame, int group);

View File

@ -28,9 +28,7 @@ ImageScaled::ImageScaled(const ImageLocator & inputLocator, const std::shared_pt
, alphaValue(SDL_ALPHA_OPAQUE)
, blitMode(mode)
{
setBodyEnabled(true);
if (mode == EImageBlitMode::ALPHA)
setShadowEnabled(true);
prepareImages();
}
std::shared_ptr<const ISharedImage> ImageScaled::getSharedImage() const
@ -92,8 +90,7 @@ void ImageScaled::setOverlayColor(const ColorRGBA & color)
void ImageScaled::playerColored(PlayerColor player)
{
playerColor = player;
if (body)
setBodyEnabled(true); // regenerate
prepareImages();
}
void ImageScaled::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
@ -106,41 +103,63 @@ void ImageScaled::adjustPalette(const ColorFilter &shifter, uint32_t colorsToSki
// TODO: implement
}
void ImageScaled::setShadowEnabled(bool on)
void ImageScaled::prepareImages()
{
assert(blitMode == EImageBlitMode::ALPHA);
if (on)
switch(blitMode)
{
locator.layer = EImageLayer::SHADOW;
locator.playerColored = PlayerColor::CANNOT_DETERMINE;
shadow = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
}
else
shadow = nullptr;
}
case EImageBlitMode::OPAQUE:
case EImageBlitMode::COLORKEY:
case EImageBlitMode::SIMPLE:
locator.layer = blitMode;
locator.playerColored = playerColor;
body = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
break;
void ImageScaled::setBodyEnabled(bool on)
{
if (on)
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)
{
locator.layer = blitMode == EImageBlitMode::ALPHA ? EImageLayer::BODY : EImageLayer::ALL;
locator.playerColored = playerColor;
body = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
case EImageBlitMode::SIMPLE:
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;
}
else
body = nullptr;
}
void ImageScaled::setOverlayEnabled(bool on)
{
assert(blitMode == EImageBlitMode::ALPHA);
if (on)
switch(blitMode)
{
locator.layer = EImageLayer::OVERLAY;
locator.playerColored = PlayerColor::CANNOT_DETERMINE;
overlay = GH.renderHandler().loadImage(locator, blitMode)->getSharedImage();
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;
}
else
overlay = nullptr;
}

View File

@ -44,6 +44,7 @@ private:
uint8_t alphaValue;
EImageBlitMode blitMode;
void prepareImages();
public:
ImageScaled(const ImageLocator & locator, const std::shared_ptr<const ISharedImage> & source, EImageBlitMode mode);
@ -60,8 +61,5 @@ public:
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override;
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;
void setShadowEnabled(bool on) override;
void setBodyEnabled(bool on) override;
void setOverlayEnabled(bool on) override;
std::shared_ptr<const ISharedImage> getSharedImage() const override;
};

View File

@ -303,22 +303,14 @@ std::shared_ptr<const ISharedImage> RenderHandler::scaleImage(const ImageLocator
if (imageFiles.count(locator))
return imageFiles.at(locator);
auto handle = image->createImageReference(locator.layer == EImageLayer::ALL ? EImageBlitMode::OPAQUE : EImageBlitMode::ALPHA);
auto handle = image->createImageReference(locator.layer);
assert(locator.scalingFactor != 1); // should be filtered-out before
handle->setBodyEnabled(locator.layer == EImageLayer::ALL || locator.layer == EImageLayer::BODY);
if (locator.layer != EImageLayer::ALL)
{
handle->setOverlayEnabled(locator.layer == EImageLayer::OVERLAY);
handle->setShadowEnabled( locator.layer == EImageLayer::SHADOW);
}
if (locator.layer == EImageLayer::ALL && locator.playerColored != PlayerColor::CANNOT_DETERMINE)
if (locator.playerColored != PlayerColor::CANNOT_DETERMINE)
handle->playerColored(locator.playerColored);
handle->scaleInteger(locator.scalingFactor);
// TODO: try to optimize image size (possibly even before scaling?) - trim image borders if they are completely transparent
auto result = handle->getSharedImage();
storeCachedImage(locator, result);
return result;
@ -331,9 +323,9 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator, E
if(adjustedLocator.image)
{
std::string imgPath = (*adjustedLocator.image).getName();
if(adjustedLocator.layer == EImageLayer::OVERLAY)
if(adjustedLocator.layer == EImageBlitMode::ONLY_OVERLAY)
imgPath += "-OVERLAY";
if(adjustedLocator.layer == EImageLayer::SHADOW)
if(adjustedLocator.layer == EImageBlitMode::ONLY_SHADOW)
imgPath += "-SHADOW";
if(CResourceHandler::get()->existsResource(ImagePath::builtin(imgPath)) ||
@ -394,7 +386,7 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageB
std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
{
return std::make_shared<SDLImageShared>(source)->createImageReference(EImageBlitMode::ALPHA);
return std::make_shared<SDLImageShared>(source)->createImageReference(EImageBlitMode::SIMPLE);
}
std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)

View File

@ -180,7 +180,7 @@ void SDLImageShared::draw(SDL_Surface * where, SDL_Palette * palette, const Poin
if (palette && surf->format->palette)
SDL_SetSurfacePalette(surf, palette);
if(surf->format->palette && mode == EImageBlitMode::ALPHA)
if(surf->format->palette && mode != EImageBlitMode::OPAQUE && mode != EImageBlitMode::COLORKEY)
{
CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift, alpha);
}
@ -425,7 +425,7 @@ void SDLImageIndexed::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove,
void SDLImageIndexed::adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask)
{
// If shadow is enabled, following colors must be skipped unconditionally
if (shadowEnabled)
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
@ -445,15 +445,10 @@ SDLImageIndexed::SDLImageIndexed(const std::shared_ptr<const ISharedImage> & ima
:SDLImageBase::SDLImageBase(image, mode)
,originalPalette(originalPalette)
{
currentPalette = SDL_AllocPalette(originalPalette->ncolors);
SDL_SetPaletteColors(currentPalette, originalPalette->colors, 0, originalPalette->ncolors);
if (mode == EImageBlitMode::ALPHA)
{
setOverlayColor(Colors::TRANSPARENCY);
setShadowTransparency(1.0);
}
preparePalette();
}
SDLImageIndexed::~SDLImageIndexed()
@ -500,36 +495,42 @@ void SDLImageIndexed::setOverlayColor(const ColorRGBA & color)
}
}
void SDLImageIndexed::setShadowEnabled(bool on)
void SDLImageIndexed::preparePalette()
{
if (on)
setShadowTransparency(1.0);
switch(blitMode)
{
case EImageBlitMode::ONLY_SHADOW:
case EImageBlitMode::ONLY_OVERLAY:
adjustPalette(ColorFilter::genAlphaShifter(0), 0);
break;
}
if (!on && blitMode == EImageBlitMode::ALPHA)
setShadowTransparency(0.0);
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;
}
shadowEnabled = on;
}
void SDLImageIndexed::setBodyEnabled(bool on)
{
if (on)
adjustPalette(ColorFilter::genEmptyShifter(), 0);
else
adjustPalette(ColorFilter::genAlphaShifter(0), 0);
bodyEnabled = on;
}
void SDLImageIndexed::setOverlayEnabled(bool on)
{
if (on)
setOverlayColor(Colors::WHITE_TRUE);
if (!on && blitMode == EImageBlitMode::ALPHA)
setOverlayColor(Colors::TRANSPARENCY);
overlayEnabled = on;
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()
@ -609,21 +610,6 @@ void SDLImageBase::setBlitMode(EImageBlitMode mode)
blitMode = mode;
}
void SDLImageRGB::setShadowEnabled(bool on)
{
// Not supported. Theoretically we can try to extract all pixels of specific colors, but better to use 8-bit images or composite images
}
void SDLImageRGB::setBodyEnabled(bool on)
{
// Not supported. Theoretically we can try to extract all pixels of specific colors, but better to use 8-bit images or composite images
}
void SDLImageRGB::setOverlayEnabled(bool on)
{
// Not supported. Theoretically we can try to extract all pixels of specific colors, but better to use 8-bit images or composite images
}
void SDLImageRGB::setOverlayColor(const ColorRGBA & color)
{}

View File

@ -89,11 +89,8 @@ class SDLImageIndexed final : public SDLImageBase
SDL_Palette * currentPalette = nullptr;
SDL_Palette * originalPalette = nullptr;
bool bodyEnabled = true;
bool shadowEnabled = false;
bool overlayEnabled = false;
void setShadowTransparency(float factor);
void preparePalette();
public:
SDLImageIndexed(const std::shared_ptr<const ISharedImage> & image, SDL_Palette * palette, EImageBlitMode mode);
~SDLImageIndexed();
@ -106,10 +103,6 @@ public:
void scaleInteger(int factor) override;
void scaleTo(const Point & size) override;
void exportBitmap(const boost::filesystem::path & path) const override;
void setShadowEnabled(bool on) override;
void setBodyEnabled(bool on) override;
void setOverlayEnabled(bool on) override;
};
class SDLImageRGB final : public SDLImageBase
@ -125,8 +118,4 @@ public:
void scaleInteger(int factor) override;
void scaleTo(const Point & size) override;
void exportBitmap(const boost::filesystem::path & path) const override;
void setShadowEnabled(bool on) override;
void setBodyEnabled(bool on) override;
void setOverlayEnabled(bool on) override;
};

View File

@ -194,12 +194,12 @@ CAnimImage::CAnimImage(const AnimationPath & name, size_t Frame, size_t Group, i
{
pos.x += x;
pos.y += y;
anim = GH.renderHandler().loadAnimation(name, EImageBlitMode::COLORKEY);
anim = GH.renderHandler().loadAnimation(name, (Flags & CCreatureAnim::CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::COLORKEY);
init();
}
CAnimImage::CAnimImage(const AnimationPath & name, size_t Frame, Rect targetPos, size_t Group, ui8 Flags):
anim(GH.renderHandler().loadAnimation(name, EImageBlitMode::COLORKEY)),
anim(GH.renderHandler().loadAnimation(name, (Flags & CCreatureAnim::CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::COLORKEY)),
frame(Frame),
group(Group),
flags(Flags),
@ -317,7 +317,7 @@ bool CAnimImage::isPlayerColored() const
}
CShowableAnim::CShowableAnim(int x, int y, const AnimationPath & name, ui8 Flags, ui32 frameTime, size_t Group, uint8_t alpha):
anim(GH.renderHandler().loadAnimation(name, (Flags & CREATURE_MODE) ? EImageBlitMode::ALPHA : EImageBlitMode::COLORKEY)),
anim(GH.renderHandler().loadAnimation(name, (Flags & CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::COLORKEY)),
group(Group),
frame(0),
first(0),
@ -430,8 +430,6 @@ void CShowableAnim::blitImage(size_t frame, size_t group, Canvas & to)
auto img = anim->getImage(frame, group);
if(img)
{
if (flags & CREATURE_MODE)
img->setShadowEnabled(true);
img->setAlpha(alpha);
to.draw(img, pos.topLeft(), src);
}

View File

@ -98,7 +98,7 @@ CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town
border = GH.renderHandler().loadImage(str->borderName, EImageBlitMode::COLORKEY);
if(!str->areaName.empty())
area = GH.renderHandler().loadImage(str->areaName, EImageBlitMode::ALPHA);
area = GH.renderHandler().loadImage(str->areaName, EImageBlitMode::SIMPLE);
}
const CBuilding * CBuildingRect::getBuilding()

View File

@ -950,7 +950,7 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, BuildingID bu
}
else if(auto uni = dynamic_cast<const CGUniversity *>(_market); uni->appearance)
{
titlePic = std::make_shared<CAnimImage>(uni->appearance->animationFile, 0);
titlePic = std::make_shared<CAnimImage>(uni->appearance->animationFile, 0, 0, 0, 0, CShowableAnim::CREATURE_MODE);
titleStr = uni->title;
speechStr = uni->speech;
}