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:
parent
c82db9d574
commit
251155d913
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user