1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-02 22:05:43 +02:00

Handle flag color overlay and creature selection overlay separately

Fixes handling of Iron Golem animation from HotA
This commit is contained in:
Ivan Savenko 2025-02-03 11:44:21 +00:00
parent ec5d4dbe5d
commit 38bb5a76e6
7 changed files with 82 additions and 44 deletions

View File

@ -200,8 +200,8 @@ CreatureAnimation::CreatureAnimation(const AnimationPath & name_, TSpeedControll
speedController(controller), speedController(controller),
once(false) once(false)
{ {
forward = GH.renderHandler().loadAnimation(name_, EImageBlitMode::WITH_SHADOW_AND_OVERLAY); forward = GH.renderHandler().loadAnimation(name_, EImageBlitMode::WITH_SHADOW_AND_SELECTION);
reverse = GH.renderHandler().loadAnimation(name_, EImageBlitMode::WITH_SHADOW_AND_OVERLAY); reverse = GH.renderHandler().loadAnimation(name_, EImageBlitMode::WITH_SHADOW_AND_SELECTION);
// if necessary, add one frame into vcmi-only group DEAD // if necessary, add one frame into vcmi-only group DEAD
if(forward->size(size_t(ECreatureAnimType::DEAD)) == 0) if(forward->size(size_t(ECreatureAnimType::DEAD)) == 0)

View File

@ -407,7 +407,7 @@ std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const AnimationPath
if(it != animations.end()) if(it != animations.end())
return it->second; return it->second;
auto ret = GH.renderHandler().loadAnimation(filename, enableOverlay ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::WITH_SHADOW); auto ret = GH.renderHandler().loadAnimation(filename, enableOverlay ? EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR: EImageBlitMode::WITH_SHADOW);
animations[filename] = ret; animations[filename] = ret;
if(generateMovementGroups) if(generateMovementGroups)

View File

@ -47,19 +47,23 @@ enum class EImageBlitMode : uint8_t
WITH_SHADOW, WITH_SHADOW,
/// RGBA, may consist from 3 separate parts: base, shadow, and overlay /// RGBA, may consist from 3 separate parts: base, shadow, and overlay
WITH_SHADOW_AND_OVERLAY, WITH_SHADOW_AND_SELECTION,
WITH_SHADOW_AND_FLAG_COLOR,
/// RGBA, contains only body, with shadow and overlay disabled /// RGBA, contains only body, with shadow and overlay disabled
ONLY_BODY, ONLY_BODY_HIDE_SELECTION,
ONLY_BODY_HIDE_FLAG_COLOR,
/// RGBA, contains only body, with shadow disabled and overlay treated as part of body /// RGBA, contains only body, with shadow disabled and overlay treated as part of body
ONLY_BODY_IGNORE_OVERLAY, ONLY_BODY_IGNORE_OVERLAY,
/// RGBA, contains only shadow /// RGBA, contains only shadow
ONLY_SHADOW, ONLY_SHADOW_HIDE_SELECTION,
ONLY_SHADOW_HIDE_FLAG_COLOR,
/// RGBA, contains only overlay /// RGBA, contains only overlay
ONLY_OVERLAY, ONLY_SELECTION,
ONLY_FLAG_COLOR,
}; };
enum class EScalingAlgorithm : int8_t enum class EScalingAlgorithm : int8_t

View File

@ -230,6 +230,7 @@ std::shared_ptr<ISharedImage> RenderHandler::loadImageFromFileUncached(const Ima
if (generated) if (generated)
return generated; return generated;
logGlobal->error("Failed to load image %s", locator.image->getOriginalName());
return std::make_shared<SDLImageShared>(ImagePath::builtin("DEFAULT")); return std::make_shared<SDLImageShared>(ImagePath::builtin("DEFAULT"));
} }
@ -292,9 +293,9 @@ std::shared_ptr<SDLImageShared> RenderHandler::loadScaledImage(const ImageLocato
std::string imagePathString = pathToLoad.getName(); std::string imagePathString = pathToLoad.getName();
if(locator.layer == EImageBlitMode::ONLY_OVERLAY) if(locator.layer == EImageBlitMode::ONLY_FLAG_COLOR || locator.layer == EImageBlitMode::ONLY_SELECTION)
imagePathString += "-OVERLAY"; imagePathString += "-OVERLAY";
if(locator.layer == EImageBlitMode::ONLY_SHADOW) if(locator.layer == EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION || locator.layer == EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR)
imagePathString += "-SHADOW"; imagePathString += "-SHADOW";
if(locator.playerColored.isValidPlayer()) if(locator.playerColored.isValidPlayer())
imagePathString += "-" + boost::to_upper_copy(GameConstants::PLAYER_COLOR_NAMES[locator.playerColored.getNum()]); imagePathString += "-" + boost::to_upper_copy(GameConstants::PLAYER_COLOR_NAMES[locator.playerColored.getNum()]);
@ -347,7 +348,10 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int
if (!locator.empty()) if (!locator.empty())
return loadImage(locator); return loadImage(locator);
else else
{
logGlobal->error("Failed to load non-existing image");
return loadImage(ImageLocator(ImagePath::builtin("DEFAULT"), mode)); return loadImage(ImageLocator(ImagePath::builtin("DEFAULT"), mode));
}
} }
std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode) std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)

View File

@ -97,8 +97,10 @@ void ScalableImageParameters::preparePalette(const SDL_Palette * originalPalette
{ {
switch(blitMode) switch(blitMode)
{ {
case EImageBlitMode::ONLY_SHADOW: case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
case EImageBlitMode::ONLY_OVERLAY: case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
case EImageBlitMode::ONLY_FLAG_COLOR:
case EImageBlitMode::ONLY_SELECTION:
adjustPalette(originalPalette, blitMode, ColorFilter::genAlphaShifter(0), 0); adjustPalette(originalPalette, blitMode, ColorFilter::genAlphaShifter(0), 0);
break; break;
} }
@ -107,37 +109,49 @@ void ScalableImageParameters::preparePalette(const SDL_Palette * originalPalette
{ {
case EImageBlitMode::SIMPLE: case EImageBlitMode::SIMPLE:
case EImageBlitMode::WITH_SHADOW: case EImageBlitMode::WITH_SHADOW:
case EImageBlitMode::ONLY_SHADOW: case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY: case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
setShadowTransparency(originalPalette, 1.0); setShadowTransparency(originalPalette, 1.0);
break; break;
case EImageBlitMode::ONLY_BODY: case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY: case EImageBlitMode::ONLY_BODY_IGNORE_OVERLAY:
case EImageBlitMode::ONLY_OVERLAY: case EImageBlitMode::ONLY_FLAG_COLOR:
case EImageBlitMode::ONLY_SELECTION:
setShadowTransparency(originalPalette, 0.0); setShadowTransparency(originalPalette, 0.0);
break; break;
} }
switch(blitMode) switch(blitMode)
{ {
case EImageBlitMode::ONLY_OVERLAY: case EImageBlitMode::ONLY_FLAG_COLOR:
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY: case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
setOverlayColor(originalPalette, Colors::WHITE_TRUE); setOverlayColor(originalPalette, Colors::WHITE_TRUE, false);
break; break;
case EImageBlitMode::ONLY_SHADOW: case EImageBlitMode::ONLY_SELECTION:
case EImageBlitMode::ONLY_BODY: case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
setOverlayColor(originalPalette, Colors::TRANSPARENCY); setOverlayColor(originalPalette, Colors::WHITE_TRUE, true);
break;
case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
setOverlayColor(originalPalette, Colors::TRANSPARENCY, false);
break;
case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
setOverlayColor(originalPalette, Colors::TRANSPARENCY, true);
break; break;
} }
} }
void ScalableImageParameters::setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color) void ScalableImageParameters::setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color, bool includeShadow)
{ {
palette->colors[5] = CSDL_Ext::toSDL(addColors(targetPalette[5], color)); palette->colors[5] = CSDL_Ext::toSDL(addColors(targetPalette[5], color));
for (int i : {6,7}) if (includeShadow)
{ {
if (colorsSimilar(originalPalette->colors[i], sourcePalette[i])) for (int i : {6,7})
palette->colors[i] = CSDL_Ext::toSDL(addColors(targetPalette[i], color)); palette->colors[i] = CSDL_Ext::toSDL(addColors(targetPalette[i], color));
} }
} }
@ -183,7 +197,7 @@ void ScalableImageParameters::setShadowTransparency(const SDL_Palette * original
void ScalableImageParameters::adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask) void ScalableImageParameters::adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask)
{ {
// If shadow is enabled, following colors must be skipped unconditionally // If shadow is enabled, following colors must be skipped unconditionally
if (blitMode == EImageBlitMode::WITH_SHADOW || blitMode == EImageBlitMode::WITH_SHADOW_AND_OVERLAY) if (blitMode == EImageBlitMode::WITH_SHADOW || blitMode == EImageBlitMode::WITH_SHADOW_AND_SELECTION || blitMode == EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR)
colorsToSkipMask |= (1 << 0) + (1 << 1) + (1 << 4); colorsToSkipMask |= (1 << 0) + (1 << 1) + (1 << 4);
// Note: here we skip first colors in the palette that are predefined in H3 images // Note: here we skip first colors in the palette that are predefined in H3 images
@ -353,7 +367,7 @@ void ScalableImageInstance::setOverlayColor(const ColorRGBA & color)
parameters.ovelayColorMultiplier = color; parameters.ovelayColorMultiplier = color;
if (parameters.palette) if (parameters.palette)
parameters.setOverlayColor(image->getPalette(), color); parameters.setOverlayColor(image->getPalette(), color, blitMode == EImageBlitMode::WITH_SHADOW_AND_SELECTION);
} }
void ScalableImageInstance::playerColored(const PlayerColor & player) void ScalableImageInstance::playerColored(const PlayerColor & player)
@ -414,7 +428,7 @@ std::shared_ptr<const ISharedImage> ScalableImageShared::loadOrGenerateImage(EIm
{ {
// optional images for 1x resolution - only try load them, don't attempt to generate // optional images for 1x resolution - only try load them, don't attempt to generate
// this block should never be called for 'body' layer - that image is loaded unconditionally before construction // this block should never be called for 'body' layer - that image is loaded unconditionally before construction
assert(mode == EImageBlitMode::ONLY_SHADOW || mode == EImageBlitMode::ONLY_OVERLAY || color != PlayerColor::CANNOT_DETERMINE); assert(mode == EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR || mode == EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION || mode == EImageBlitMode::ONLY_FLAG_COLOR || mode == EImageBlitMode::ONLY_SELECTION || color != PlayerColor::CANNOT_DETERMINE);
return nullptr; return nullptr;
} }
@ -427,7 +441,7 @@ std::shared_ptr<const ISharedImage> ScalableImageShared::loadOrGenerateImage(EIm
{ {
if (scaling == 1) if (scaling == 1)
{ {
if (mode == EImageBlitMode::ONLY_SHADOW || mode == EImageBlitMode::ONLY_OVERLAY || color != PlayerColor::CANNOT_DETERMINE) if (mode == EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR || mode == EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION || mode == EImageBlitMode::ONLY_FLAG_COLOR || mode == EImageBlitMode::ONLY_SELECTION || color != PlayerColor::CANNOT_DETERMINE)
{ {
ScalableImageParameters parameters(getPalette(), mode); ScalableImageParameters parameters(getPalette(), mode);
return loadedImage->scaleInteger(scalingFactor, parameters.palette, mode); return loadedImage->scaleInteger(scalingFactor, parameters.palette, mode);
@ -464,9 +478,13 @@ void ScalableImageShared::loadScaledImages(int8_t scalingFactor, PlayerColor col
scaled[scalingFactor].body[0] = loadOrGenerateImage(locator.layer, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]); scaled[scalingFactor].body[0] = loadOrGenerateImage(locator.layer, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
break; break;
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY: case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
case EImageBlitMode::ONLY_BODY: case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]); scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_SELECTION, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
break;
case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
scaled[scalingFactor].body[0] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].body[0]);
break; break;
case EImageBlitMode::WITH_SHADOW: case EImageBlitMode::WITH_SHADOW:
@ -486,9 +504,13 @@ void ScalableImageShared::loadScaledImages(int8_t scalingFactor, PlayerColor col
scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(locator.layer, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]); scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(locator.layer, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
break; break;
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY: case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
case EImageBlitMode::ONLY_BODY: case EImageBlitMode::ONLY_BODY_HIDE_SELECTION:
scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]); scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_SELECTION, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
break;
case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
case EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR:
scaled[scalingFactor].playerColored[1+color.getNum()] = loadOrGenerateImage(EImageBlitMode::ONLY_BODY_HIDE_FLAG_COLOR, scalingFactor, color, scaled[1].playerColored[1+color.getNum()]);
break; break;
case EImageBlitMode::WITH_SHADOW: case EImageBlitMode::WITH_SHADOW:
@ -503,9 +525,13 @@ void ScalableImageShared::loadScaledImages(int8_t scalingFactor, PlayerColor col
switch(locator.layer) switch(locator.layer)
{ {
case EImageBlitMode::WITH_SHADOW: case EImageBlitMode::WITH_SHADOW:
case EImageBlitMode::ONLY_SHADOW: case EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION:
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY: case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
scaled[scalingFactor].shadow[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SHADOW, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].shadow[0]); scaled[scalingFactor].shadow[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SHADOW_HIDE_SELECTION, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].shadow[0]);
break;
case EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR:
case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
scaled[scalingFactor].shadow[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SHADOW_HIDE_FLAG_COLOR, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].shadow[0]);
break; break;
default: default:
break; break;
@ -516,9 +542,13 @@ void ScalableImageShared::loadScaledImages(int8_t scalingFactor, PlayerColor col
{ {
switch(locator.layer) switch(locator.layer)
{ {
case EImageBlitMode::ONLY_OVERLAY: case EImageBlitMode::ONLY_FLAG_COLOR:
case EImageBlitMode::WITH_SHADOW_AND_OVERLAY: case EImageBlitMode::WITH_SHADOW_AND_FLAG_COLOR:
scaled[scalingFactor].overlay[0] = loadOrGenerateImage(EImageBlitMode::ONLY_OVERLAY, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].overlay[0]); scaled[scalingFactor].overlay[0] = loadOrGenerateImage(EImageBlitMode::ONLY_FLAG_COLOR, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].overlay[0]);
break;
case EImageBlitMode::ONLY_SELECTION:
case EImageBlitMode::WITH_SHADOW_AND_SELECTION:
scaled[scalingFactor].overlay[0] = loadOrGenerateImage(EImageBlitMode::ONLY_SELECTION, scalingFactor, PlayerColor::CANNOT_DETERMINE, scaled[1].overlay[0]);
break; break;
default: default:
break; break;

View File

@ -39,7 +39,7 @@ struct ScalableImageParameters : boost::noncopyable
void setShadowTransparency(const SDL_Palette * originalPalette, float factor); void setShadowTransparency(const SDL_Palette * originalPalette, float factor);
void shiftPalette(const SDL_Palette * originalPalette, uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove); void shiftPalette(const SDL_Palette * originalPalette, uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove);
void playerColored(PlayerColor player); void playerColored(PlayerColor player);
void setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color); void setOverlayColor(const SDL_Palette * originalPalette, const ColorRGBA & color, bool includeShadow);
void preparePalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode); void preparePalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode);
void adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask); void adjustPalette(const SDL_Palette * originalPalette, EImageBlitMode blitMode, const ColorFilter & shifter, uint32_t colorsToSkipMask);
}; };

View File

@ -195,12 +195,12 @@ CAnimImage::CAnimImage(const AnimationPath & name, size_t Frame, size_t Group, i
{ {
pos.x += x; pos.x += x;
pos.y += y; pos.y += y;
anim = GH.renderHandler().loadAnimation(name, (Flags & CCreatureAnim::CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::COLORKEY); anim = GH.renderHandler().loadAnimation(name, (Flags & CCreatureAnim::CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_SELECTION: EImageBlitMode::COLORKEY);
init(); init();
} }
CAnimImage::CAnimImage(const AnimationPath & name, size_t Frame, Rect targetPos, size_t Group, ui8 Flags): CAnimImage::CAnimImage(const AnimationPath & name, size_t Frame, Rect targetPos, size_t Group, ui8 Flags):
anim(GH.renderHandler().loadAnimation(name, (Flags & CCreatureAnim::CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::COLORKEY)), anim(GH.renderHandler().loadAnimation(name, (Flags & CCreatureAnim::CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_SELECTION : EImageBlitMode::COLORKEY)),
frame(Frame), frame(Frame),
group(Group), group(Group),
flags(Flags), flags(Flags),
@ -318,7 +318,7 @@ bool CAnimImage::isPlayerColored() const
} }
CShowableAnim::CShowableAnim(int x, int y, const AnimationPath & name, ui8 Flags, ui32 frameTime, size_t Group, uint8_t alpha): 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::WITH_SHADOW_AND_OVERLAY : EImageBlitMode::COLORKEY)), anim(GH.renderHandler().loadAnimation(name, (Flags & CREATURE_MODE) ? EImageBlitMode::WITH_SHADOW_AND_SELECTION : EImageBlitMode::COLORKEY)),
group(Group), group(Group),
frame(0), frame(0),
first(0), first(0),