1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-29 21:56:54 +02:00

Merge pull request from vcmi/guiCleanup2

Gui cleanup2
This commit is contained in:
ArseniyShestakov 2017-09-07 02:46:54 +03:00 committed by GitHub
commit d01ecbba90
21 changed files with 398 additions and 532 deletions

@ -29,12 +29,9 @@ static long long pow(long long a, int b)
CDefHandler::CDefHandler()
{
notFreeImgs = false;
}
CDefHandler::~CDefHandler()
{
if (notFreeImgs)
return;
for (auto & elem : ourImages)
{
if (elem.bitmap)
@ -44,11 +41,6 @@ CDefHandler::~CDefHandler()
}
}
}
CDefEssential::~CDefEssential()
{
for(auto & elem : ourImages)
SDL_FreeSurface(elem.bitmap);
}
void CDefHandler::openFromMemory(ui8 *table, const std::string & name)
{
@ -350,14 +342,6 @@ SDL_Surface * CDefHandler::getSprite (int SIndex, const ui8 * FDef, const SDL_Co
return ret;
}
CDefEssential * CDefHandler::essentialize()
{
auto ret = new CDefEssential();
ret->ourImages = ourImages;
notFreeImgs = true;
return ret;
}
CDefHandler * CDefHandler::giveDef(const std::string & defName)
{
ResourceID resID(std::string("SPRITES/") + defName, EResType::ANIMATION);
@ -369,12 +353,4 @@ CDefHandler * CDefHandler::giveDef(const std::string & defName)
nh->openFromMemory(data.get(), defName);
return nh;
}
CDefEssential * CDefHandler::giveDefEss(const std::string & defName)
{
CDefEssential * ret;
CDefHandler * temp = giveDef(defName);
ret = temp->essentialize();
delete temp;
return ret;
}

@ -66,12 +66,6 @@ struct SSpriteDef
ui32 TopMargin;
} PACKED_STRUCT;
class CDefEssential //DefHandler with images only
{
public:
std::vector<Cimage> ourImages;
~CDefEssential();
};
class CDefHandler
{
@ -84,20 +78,17 @@ private:
int group;
} ;
std::vector<SEntry> SEntries ;
void openFromMemory(ui8 * table, const std::string & name);
void openFromMemory(ui8 * table, const std::string & name);
SDL_Surface * getSprite (int SIndex, const ui8 * FDef, const SDL_Color * palette) const;
public:
int width, height; //width and height
std::string defName;
std::vector<Cimage> ourImages;
bool notFreeImgs;
CDefHandler();
~CDefHandler();
CDefEssential * essentialize();
static CDefHandler * giveDef(const std::string & defName);
static CDefEssential * giveDefEss(const std::string & defName);
};

@ -232,16 +232,10 @@ std::shared_ptr<CAnimation> Graphics::loadHeroFlagAnimation(const std::string &
for(const auto & rotation : rotations)
{
const int sourceGroup = rotation.first;
const int targetGroup = rotation.second;
const int sourceGroup = rotation.first;
const int targetGroup = rotation.second;
for(size_t frame = 0; frame < anim->size(sourceGroup); ++frame)
{
anim->duplicateImage(sourceGroup, frame, targetGroup);
IImage * image = anim->getImage(frame, targetGroup);
image->verticalFlip();
}
anim->createFlippedGroup(sourceGroup, targetGroup);
}
return anim;
@ -262,15 +256,10 @@ std::shared_ptr<CAnimation> Graphics::loadHeroAnimation(const std::string &name)
for(const auto & rotation : rotations)
{
const int sourceGroup = rotation.first;
const int targetGroup = rotation.second;
const int sourceGroup = rotation.first;
const int targetGroup = rotation.second;
for(size_t frame = 0; frame < anim->size(sourceGroup); ++frame)
{
anim->duplicateImage(sourceGroup, frame, targetGroup);
IImage * image = anim->getImage(frame, targetGroup);
image->verticalFlip();
}
anim->createFlippedGroup(sourceGroup, targetGroup);
}
return anim;

@ -16,11 +16,11 @@
#include "CBattleInterface.h"
#include "CCreatureAnimation.h"
#include "../CDefHandler.h"
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../Graphics.h"
#include "../gui/CAnimation.h"
#include "../gui/CCursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Extensions.h"
@ -58,13 +58,13 @@ bool CBattleAnimation::isEarliest(bool perStackConcurrency)
{
int lowestMoveID = owner->animIDhelper + 5;
CBattleStackAnimation * thAnim = dynamic_cast<CBattleStackAnimation *>(this);
CSpellEffectAnimation * thSen = dynamic_cast<CSpellEffectAnimation *>(this);
CEffectAnimation * thSen = dynamic_cast<CEffectAnimation *>(this);
for(auto & elem : owner->pendingAnims)
{
CBattleStackAnimation * stAnim = dynamic_cast<CBattleStackAnimation *>(elem.first);
CSpellEffectAnimation * sen = dynamic_cast<CSpellEffectAnimation *>(elem.first);
CEffectAnimation * sen = dynamic_cast<CEffectAnimation *>(elem.first);
if(perStackConcurrency && stAnim && thAnim && stAnim->stack->ID != thAnim->stack->ID)
continue;
@ -171,7 +171,7 @@ bool CDefenceAnimation::init()
if(attAnim && attAnim->stack->ID != stack->ID)
continue;
CSpellEffectAnimation * sen = dynamic_cast<CSpellEffectAnimation *>(elem.first);
CEffectAnimation * sen = dynamic_cast<CEffectAnimation *>(elem.first);
if (sen)
continue;
@ -243,7 +243,7 @@ CCreatureAnim::EAnimType CDefenceAnimation::getMyAnimType()
if(killed)
return CCreatureAnim::DEATH;
if (vstd::contains(stack->state, EBattleStackState::DEFENDING_ANIM))
if(vstd::contains(stack->state, EBattleStackState::DEFENDING_ANIM))
return CCreatureAnim::DEFENCE;
return CCreatureAnim::HITTED;
@ -270,10 +270,15 @@ void CDefenceAnimation::nextFrame()
void CDefenceAnimation::endAnim()
{
if (killed)
if(killed)
{
myAnim->setType(CCreatureAnim::DEAD);
}
else
{
myAnim->setType(CCreatureAnim::HOLDING);
}
CBattleAnimation::endAnim();
@ -785,13 +790,13 @@ bool CShootingAnimation::init()
spi.dx = animSpeed;
spi.dy = 0;
SDL_Surface * img = owner->idToProjectile[spi.creID]->ourImages[0].bitmap;
IImage * img = owner->idToProjectile[spi.creID]->getImage(0);
// Add explosion anim
Point animPos(destPos.x - 126 + img->w / 2,
destPos.y - 105 + img->h / 2);
Point animPos(destPos.x - 126 + img->width() / 2,
destPos.y - 105 + img->height() / 2);
owner->addNewAnim( new CSpellEffectAnimation(owner, catapultDamage ? "SGEXPL.DEF" : "CSGRCK.DEF", animPos.x, animPos.y));
owner->addNewAnim( new CEffectAnimation(owner, catapultDamage ? "SGEXPL.DEF" : "CSGRCK.DEF", animPos.x, animPos.y));
}
auto & angles = shooterInfo->animation.missleFrameAngles;
@ -801,7 +806,7 @@ bool CShootingAnimation::init()
owner->initStackProjectile(shooter);
// only frames below maxFrame are usable: anything higher is either no present or we don't know when it should be used
size_t maxFrame = std::min<size_t>(angles.size(), owner->idToProjectile.at(spi.creID)->ourImages.size());
size_t maxFrame = std::min<size_t>(angles.size(), owner->idToProjectile.at(spi.creID)->size(0));
assert(maxFrame > 0);
@ -872,35 +877,40 @@ void CShootingAnimation::endAnim()
delete this;
}
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx, int _dy, bool _Vflip, bool _alignToBottom)
:CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), x(-1), y(-1), dx(_dx), dy(_dy), Vflip(_Vflip), alignToBottom(_alignToBottom)
CEffectAnimation::CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip, bool _alignToBottom)
: CBattleAnimation(_owner),
destTile(BattleHex::INVALID),
customAnim(_customAnim),
x(_x),
y(_y),
dx(_dx),
dy(_dy),
Vflip(_Vflip),
alignToBottom(_alignToBottom)
{
logAnim->debug("Created spell anim for effect #%d", effect);
logAnim->debug("Created effect animation %s", customAnim);
}
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip, bool _alignToBottom)
:CBattleAnimation(_owner), effect(-1), destTile(BattleHex::INVALID), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy), Vflip(_Vflip), alignToBottom(_alignToBottom)
CEffectAnimation::CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip, bool _alignToBottom)
: CBattleAnimation(_owner),
destTile(_destTile),
customAnim(_customAnim),
x(-1),
y(-1),
dx(0),
dy(0),
Vflip(_Vflip),
alignToBottom(_alignToBottom)
{
logAnim->debug("Created spell anim for %s", customAnim);
}
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip, bool _alignToBottom)
:CBattleAnimation(_owner), effect(-1), destTile(_destTile), customAnim(_customAnim), x(-1), y(-1), dx(0), dy(0), Vflip(_Vflip), alignToBottom(_alignToBottom)
{
logAnim->debug("Created spell anim for %s", customAnim);
logAnim->debug("Created effect animation %s", customAnim);
}
bool CSpellEffectAnimation::init()
bool CEffectAnimation::init()
{
if(!isEarliest(true))
return false;
if(customAnim.empty() && effect != ui32(-1) && !graphics->battleACToDef[effect].empty())
{
customAnim = graphics->battleACToDef[effect][0];
}
if(customAnim.empty())
{
endAnim();
@ -909,97 +919,88 @@ bool CSpellEffectAnimation::init()
const bool areaEffect = (!destTile.isValid() && x == -1 && y == -1);
std::shared_ptr<CAnimation> animation = std::make_shared<CAnimation>(customAnim);
animation->preload();
if(Vflip)
animation->verticalFlip();
IImage * first = animation->getImage(0, 0, true);
if(!first)
{
endAnim();
return false;
}
if(areaEffect) //f.e. armageddon
{
CDefHandler * anim = CDefHandler::giveDef(customAnim);
for(int i=0; i * anim->width < owner->pos.w ; ++i)
for(int i=0; i * first->width() < owner->pos.w ; ++i)
{
for(int j=0; j * anim->height < owner->pos.h ; ++j)
for(int j=0; j * first->height() < owner->pos.h ; ++j)
{
BattleEffect be;
be.effectID = ID;
be.anim = CDefHandler::giveDef(customAnim);
if (Vflip)
{
for (auto & elem : be.anim->ourImages)
{
CSDL_Ext::VflipSurf(elem.bitmap);
}
}
be.animation = animation;
be.currentFrame = 0;
be.maxFrame = be.anim->ourImages.size();
be.x = i * anim->width + owner->pos.x;
be.y = j * anim->height + owner->pos.y;
be.x = i * first->width() + owner->pos.x;
be.y = j * first->height() + owner->pos.y;
be.position = BattleHex::INVALID;
owner->battleEffects.push_back(be);
}
}
delete anim;
}
else // Effects targeted at a specific creature/hex.
{
const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(destTile, false);
Rect & tilePos = owner->bfield[destTile]->pos;
BattleEffect be;
be.effectID = ID;
be.animation = animation;
be.currentFrame = 0;
const CStack* destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(destTile, false);
Rect & tilePos = owner->bfield[destTile]->pos;
BattleEffect be;
be.effectID = ID;
be.anim = CDefHandler::giveDef(customAnim);
if (Vflip)
{
for (auto & elem : be.anim->ourImages)
{
CSDL_Ext::VflipSurf(elem.bitmap);
}
}
be.currentFrame = 0;
be.maxFrame = be.anim->ourImages.size();
//todo: lightning anim frame count override
//todo: lightning anim frame count override
// if(effect == 1)
// be.maxFrame = 3;
if(x == -1)
{
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
}
if(x == -1)
{
be.x = tilePos.x + tilePos.w/2 - first->width()/2;
}
else
{
be.x = x;
}
if(y == -1)
{
if(alignToBottom)
be.y = tilePos.y + tilePos.h - first->height();
else
{
be.x = x;
}
be.y = tilePos.y - first->height()/2;
}
else
{
be.y = y;
}
if(y == -1)
{
if(alignToBottom)
be.y = tilePos.y + tilePos.h - be.anim->height;
else
be.y = tilePos.y - be.anim->height/2;
}
else
{
be.y = y;
}
// Correction for 2-hex creatures.
if(destStack != nullptr && destStack->doubleWide())
be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
// Correction for 2-hex creatures.
if (destStack != nullptr && destStack->doubleWide())
be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
//Indicate if effect should be drawn on top of everything or just on top of the hex
be.position = destTile;
owner->battleEffects.push_back(be);
//Indicate if effect should be drawn on top of everything or just on top of the hex
be.position = destTile;
owner->battleEffects.push_back(be);
}
//battleEffects
return true;
}
void CSpellEffectAnimation::nextFrame()
void CEffectAnimation::nextFrame()
{
//notice: there may be more than one effect in owner->battleEffects correcponding to this animation (ie. armageddon)
for(auto & elem : owner->battleEffects)
@ -1008,7 +1009,7 @@ void CSpellEffectAnimation::nextFrame()
{
elem.currentFrame += AnimationControls::getSpellEffectSpeed() * GH.mainFPSmng->getElapsedMilliseconds() / 1000;
if(elem.currentFrame >= elem.maxFrame)
if(elem.currentFrame >= elem.animation->size())
{
endAnim();
break;
@ -1022,7 +1023,7 @@ void CSpellEffectAnimation::nextFrame()
}
}
void CSpellEffectAnimation::endAnim()
void CEffectAnimation::endAnim()
{
CBattleAnimation::endAnim();
@ -1038,7 +1039,6 @@ void CSpellEffectAnimation::endAnim()
for(auto & elem : toDel)
{
delete elem->anim;
owner->battleEffects.erase(elem);
}

@ -208,16 +208,15 @@ public:
void endAnim() override;
//last two params only for catapult attacks
CShootingAnimation(CBattleInterface * _owner, const CStack * attacker, BattleHex _dest,
const CStack * _attacked, bool _catapult = false, int _catapultDmg = 0);
CShootingAnimation(CBattleInterface * _owner, const CStack * attacker, BattleHex _dest,
const CStack * _attacked, bool _catapult = false, int _catapultDmg = 0);
virtual ~CShootingAnimation(){};
};
/// This class manages a spell effect animation
class CSpellEffectAnimation : public CBattleAnimation
/// This class manages effect animation
class CEffectAnimation : public CBattleAnimation
{
private:
ui32 effect;
BattleHex destTile;
std::string customAnim;
int x, y, dx, dy;
@ -228,8 +227,7 @@ public:
void nextFrame() override;
void endAnim() override;
CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);
CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);
CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip = false, bool _alignToBottom = false);
virtual ~CSpellEffectAnimation(){};
CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);
CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip = false, bool _alignToBottom = false);
virtual ~CEffectAnimation(){};
};

@ -23,6 +23,7 @@
#include "../CPlayerInterface.h"
#include "../CVideoHandler.h"
#include "../Graphics.h"
#include "../gui/CAnimation.h"
#include "../gui/CCursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Extensions.h"
@ -263,7 +264,10 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
battleImage = hero1->type->heroClass->imageBattleMale;
attackingHero = new CBattleHero(battleImage, false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : nullptr, this);
attackingHero->pos = genRect(attackingHero->dh->ourImages[0].bitmap->h, attackingHero->dh->ourImages[0].bitmap->w, pos.x - 43, pos.y - 19);
IImage * img = attackingHero->animation->getImage(0, 0, true);
if(img)
attackingHero->pos = genRect(img->height(), img->width(), pos.x - 43, pos.y - 19);
}
else
{
@ -278,7 +282,10 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
battleImage = hero2->type->heroClass->imageBattleMale;
defendingHero = new CBattleHero(battleImage, true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : nullptr, this);
defendingHero->pos = genRect(defendingHero->dh->ourImages[0].bitmap->h, defendingHero->dh->ourImages[0].bitmap->w, pos.x + 693, pos.y - 19);
IImage * img = defendingHero->animation->getImage(0, 0, true);
if(img)
defendingHero->pos = genRect(img->height(), img->width(), pos.x + 693, pos.y - 19);
}
else
{
@ -425,9 +432,6 @@ CBattleInterface::~CBattleInterface()
for (auto & elem : creAnims)
delete elem.second;
for (auto & elem : idToProjectile)
delete elem.second;
for (auto & elem : idToObstacle)
delete elem.second;
@ -999,20 +1003,21 @@ void CBattleInterface::newStack(const CStack *stack)
void CBattleInterface::initStackProjectile(const CStack * stack)
{
CDefHandler *&projectile = idToProjectile[stack->getCreature()->idNumber];
const CCreature *creature;//creature whose shots should be loaded
if (stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
const CCreature * creature;//creature whose shots should be loaded
if(stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
creature = CGI->creh->creatures[siegeH->town->town->clientInfo.siegeShooter];
else
creature = stack->getCreature();
projectile = CDefHandler::giveDef(creature->animation.projectileImageName);
std::shared_ptr<CAnimation> projectile = std::make_shared<CAnimation>(creature->animation.projectileImageName);
projectile->preload();
for (auto & elem : projectile->ourImages) //alpha transforming
{
CSDL_Ext::alphaTransform(elem.bitmap);
}
if(projectile->size(1) != 0)
logAnim->error("Expected empty group 1 in stack projectile");
else
projectile->createFlippedGroup(0, 1);
idToProjectile[stack->getCreature()->idNumber] = projectile;
}
void CBattleInterface::stackRemoved(int stackID)
@ -1216,7 +1221,7 @@ void CBattleInterface::stackIsCatapulting(const CatapultAttack & ca)
{
Point destPos = CClickableHex::getXYUnitAnim(attackInfo.destinationTile, nullptr, this) + Point(99, 120);
addNewAnim(new CSpellEffectAnimation(this, "SGEXPL.DEF", destPos.x, destPos.y));
addNewAnim(new CEffectAnimation(this, "SGEXPL.DEF", destPos.x, destPos.y));
}
}
@ -1304,20 +1309,23 @@ void CBattleInterface::spellCast(const BattleSpellCast *sc)
std::string animToDisplay = spell.animationInfo.selectProjectile(angle);
if (!animToDisplay.empty())
if(!animToDisplay.empty())
{
//TODO: calculate inside CEffectAnimation
std::shared_ptr<CAnimation> tmp = std::make_shared<CAnimation>(animToDisplay);
tmp->load(0, 0);
IImage * first = tmp->getImage(0, 0);
//displaying animation
CDefEssential *animDef = CDefHandler::giveDefEss(animToDisplay);
double diffX = (destcoord.x - srccoord.x)*(destcoord.x - srccoord.x);
double diffY = (destcoord.y - srccoord.y)*(destcoord.y - srccoord.y);
double distance = sqrt(diffX + diffY);
int steps = distance / AnimationControls::getSpellEffectSpeed() + 1;
int dx = (destcoord.x - srccoord.x - animDef->ourImages[0].bitmap->w)/steps;
int dy = (destcoord.y - srccoord.y - animDef->ourImages[0].bitmap->h)/steps;
int dx = (destcoord.x - srccoord.x - first->width())/steps;
int dy = (destcoord.y - srccoord.y - first->height())/steps;
delete animDef;
addNewAnim(new CSpellEffectAnimation(this, animToDisplay, srccoord.x, srccoord.y, dx, dy, Vflip));
addNewAnim(new CEffectAnimation(this, animToDisplay, srccoord.x, srccoord.y, dx, dy, Vflip));
}
}
waitForAnims();
@ -1349,8 +1357,8 @@ void CBattleInterface::spellCast(const BattleSpellCast *sc)
{
Point leftHero = Point(15, 30) + pos;
Point rightHero = Point(755, 30) + pos;
addNewAnim(new CSpellEffectAnimation(this, sc->side ? "SP07_A.DEF" : "SP07_B.DEF", leftHero.x, leftHero.y, 0, 0, false));
addNewAnim(new CSpellEffectAnimation(this, sc->side ? "SP07_B.DEF" : "SP07_A.DEF", rightHero.x, rightHero.y, 0, 0, false));
addNewAnim(new CEffectAnimation(this, sc->side ? "SP07_A.DEF" : "SP07_B.DEF", leftHero.x, leftHero.y, 0, 0, false));
addNewAnim(new CEffectAnimation(this, sc->side ? "SP07_B.DEF" : "SP07_A.DEF", rightHero.x, rightHero.y, 0, 0, false));
}
}
@ -1413,9 +1421,11 @@ void CBattleInterface::castThisSpell(SpellID spellID)
}
}
void CBattleInterface::displayEffect(ui32 effect, int destTile)
void CBattleInterface::displayEffect(ui32 effect, BattleHex destTile)
{
addNewAnim(new CSpellEffectAnimation(this, effect, destTile, 0, 0, false));
std::string customAnim = graphics->battleACToDef[effect][0];
addNewAnim(new CEffectAnimation(this, customAnim, destTile));
}
void CBattleInterface::displaySpellAnimation(const CSpell::TAnimation & animation, BattleHex destinationTile)
@ -1426,7 +1436,7 @@ void CBattleInterface::displaySpellAnimation(const CSpell::TAnimation & animatio
}
else
{
addNewAnim(new CSpellEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
addNewAnim(new CEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
}
}
@ -2732,7 +2742,7 @@ void CBattleInterface::obstaclePlaced(const CObstacleInstance & oi)
//we assume here that effect graphics have the same size as the usual obstacle image
// -> if we know how to blit obstacle, let's blit the effect in the same place
Point whereTo = getObstaclePosition(getObstacleImage(oi), oi);
addNewAnim(new CSpellEffectAnimation(this, defname, whereTo.x, whereTo.y));
addNewAnim(new CEffectAnimation(this, defname, whereTo.x, whereTo.y));
//TODO we need to wait after playing sound till it's finished, otherwise it overlaps and sounds really bad
//CCS->soundh->playSound(sound);
@ -3166,23 +3176,18 @@ void CBattleInterface::showProjectiles(SDL_Surface *to)
continue; // wait...
}
SDL_Surface *image = idToProjectile[it->creID]->ourImages[it->frameNum].bitmap;
size_t group = it->reverse ? 1 : 0;
IImage * image = idToProjectile[it->creID]->getImage(it->frameNum, group, true);
SDL_Rect dst;
dst.h = image->h;
dst.w = image->w;
dst.x = it->x - dst.w / 2;
dst.y = it->y - dst.h / 2;
if(image)
{
SDL_Rect dst;
dst.h = image->height();
dst.w = image->width();
dst.x = it->x - dst.w / 2;
dst.y = it->y - dst.h / 2;
if (it->reverse)
{
SDL_Surface *rev = CSDL_Ext::verticalFlip(image);
CSDL_Ext::blit8bppAlphaTo24bpp(rev, nullptr, to, &dst);
SDL_FreeSurface(rev);
}
else
{
CSDL_Ext::blit8bppAlphaTo24bpp(image, nullptr, to, &dst);
image->draw(to, &dst, nullptr);
}
// Update projectile
@ -3200,7 +3205,7 @@ void CBattleInterface::showProjectiles(SDL_Surface *to)
it->y = it->catapultInfo->calculateY(it->x);
++(it->frameNum);
it->frameNum %= idToProjectile[it->creID]->ourImages.size();
it->frameNum %= idToProjectile[it->creID]->size(0);
}
else
{
@ -3368,11 +3373,13 @@ void CBattleInterface::showBattleEffects(SDL_Surface *to, const std::vector<cons
for (auto & elem : battleEffects)
{
int currentFrame = floor(elem->currentFrame);
currentFrame %= elem->anim->ourImages.size();
currentFrame %= elem->animation->size();
SDL_Surface *bitmapToBlit = elem->anim->ourImages[currentFrame].bitmap;
SDL_Rect temp_rect = genRect(bitmapToBlit->h, bitmapToBlit->w, elem->x, elem->y);
SDL_BlitSurface(bitmapToBlit, nullptr, to, &temp_rect);
IImage * img = elem->animation->getImage(currentFrame);
SDL_Rect temp_rect = genRect(img->height(), img->width(), elem->x, elem->y);
img->draw(to, &temp_rect, nullptr);
}
}

@ -48,6 +48,7 @@ struct BattleHex;
struct InfoAboutHero;
struct BattleAction;
class CBattleGameInterface;
class CAnimation;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo
@ -67,8 +68,7 @@ struct BattleEffect
{
int x, y; //position on the screen
float currentFrame;
int maxFrame;
CDefHandler *anim; //animation to display
std::shared_ptr<CAnimation> animation;
int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
BattleHex position; //Indicates if effect which hex the effect is drawn on
};
@ -120,6 +120,7 @@ class CBattleInterface : public CIntObject
};
private:
SDL_Surface *background, *menu, *amountNormal, *amountNegative, *amountPositive, *amountEffNeutral, *cellBorders, *backgroundWithHexes;
CButton *bOptions, *bSurrender, *bFlee, *bAutofight, *bSpell,
* bWait, *bDefence, *bConsoleUp, *bConsoleDown, *btactNext, *btactEnd;
CBattleConsole *console;
@ -128,7 +129,9 @@ private:
const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
const CGHeroInstance *attackingHeroInstance, *defendingHeroInstance;
std::map<int, CCreatureAnimation *> creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
std::map<int, CDefHandler *> idToProjectile; //projectiles of creatures (creatureID, defhandler)
std::map<int, std::shared_ptr<CAnimation>> idToProjectile;
std::map<int, CDefHandler *> idToObstacle; //obstacles located on the battlefield
std::map<int, SDL_Surface *> idToAbsoluteObstacle; //obstacles located on the battlefield
@ -340,7 +343,7 @@ public:
void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell
void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook
void displayEffect(ui32 effect, int destTile); //displays custom effect on the battlefield
void displayEffect(ui32 effect, BattleHex destTile); //displays custom effect on the battlefield
void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation
void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
@ -376,7 +379,7 @@ public:
friend class CBattleResultWindow;
friend class CBattleHero;
friend class CSpellEffectAnimation;
friend class CEffectAnimation;
friend class CBattleStackAnimation;
friend class CReverseAnimation;
friend class CDefenceAnimation;

@ -13,13 +13,13 @@
#include "CBattleInterface.h"
#include "../CBitmapHandler.h"
#include "../CDefHandler.h"
#include "../CGameInfo.h"
#include "../CMessage.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../CVideoHandler.h"
#include "../Graphics.h"
#include "../gui/CAnimation.h"
#include "../gui/CCursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Extensions.h"
@ -129,13 +129,18 @@ CBattleConsole::CBattleConsole() : lastShown(-1), alterTxt(""), whoSetAlter(0)
void CBattleHero::show(SDL_Surface * to)
{
IImage * flagFrame = flagAnimation->getImage(flagAnim, 0, true);
if(!flagFrame)
return;
//animation of flag
SDL_Rect temp_rect;
if(flip)
{
temp_rect = genRect(
flag->ourImages[flagAnim].bitmap->h,
flag->ourImages[flagAnim].bitmap->w,
flagFrame->height(),
flagFrame->width(),
pos.x + 61,
pos.y + 39);
@ -143,28 +148,30 @@ void CBattleHero::show(SDL_Surface * to)
else
{
temp_rect = genRect(
flag->ourImages[flagAnim].bitmap->h,
flag->ourImages[flagAnim].bitmap->w,
flagFrame->height(),
flagFrame->width(),
pos.x + 72,
pos.y + 39);
}
CSDL_Ext::blit8bppAlphaTo24bpp(
flag->ourImages[flagAnim].bitmap,
nullptr,
screen,
&temp_rect);
flagFrame->draw(screen, &temp_rect, nullptr); //FIXME: why screen?
//animation of hero
SDL_Rect rect = pos;
CSDL_Ext::blit8bppAlphaTo24bpp(dh->ourImages[currentFrame].bitmap, nullptr, to, &rect);
if ( ++animCount == 4 )
IImage * heroFrame = animation->getImage(currentFrame, phase, true);
if(!heroFrame)
return;
heroFrame->draw(to, &rect, nullptr);
if(++animCount >= 4)
{
animCount = 0;
if ( ++flagAnim >= flag->ourImages.size())
if(++flagAnim >= flagAnimation->size(0))
flagAnim = 0;
if ( ++currentFrame >= lastFrame)
if(++currentFrame >= lastFrame)
switchToNextPhase();
}
}
@ -190,7 +197,13 @@ void CBattleHero::clickLeft(tribool down, bool previousState)
if(myOwner->spellDestSelectMode) //we are casting a spell
return;
if(myHero != nullptr && !down && myOwner->myTurn && myOwner->getCurrentPlayerInterface()->cb->battleCanCastSpell(myHero, ECastingMode::HERO_CASTING) == ESpellCastProblem::OK) //check conditions
if(boost::logic::indeterminate(down))
return;
if(!myHero || down || !myOwner->myTurn)
return;
if(myOwner->getCurrentPlayerInterface()->cb->battleCanCastSpell(myHero, ECastingMode::HERO_CASTING) == ESpellCastProblem::OK) //check conditions
{
for(int it=0; it<GameConstants::BFIELD_SIZE; ++it) //do nothing when any hex is hovered - hero's animation overlaps battlefield
{
@ -205,6 +218,9 @@ void CBattleHero::clickLeft(tribool down, bool previousState)
void CBattleHero::clickRight(tribool down, bool previousState)
{
if(boost::logic::indeterminate(down))
return;
Point windowPosition;
windowPosition.x = (!flip) ? myOwner->pos.topLeft().x + 1 : myOwner->pos.topRight().x - 79;
windowPosition.y = myOwner->pos.y + 135;
@ -220,24 +236,19 @@ void CBattleHero::clickRight(tribool down, bool previousState)
void CBattleHero::switchToNextPhase()
{
if (phase != nextPhase)
if(phase != nextPhase)
{
phase = nextPhase;
//find first and last frames of our animation
for (firstFrame = 0;
firstFrame < dh->ourImages.size() && dh->ourImages[firstFrame].groupNumber != phase;
firstFrame++);
firstFrame = 0;
for (lastFrame = firstFrame;
lastFrame < dh->ourImages.size() && dh->ourImages[lastFrame].groupNumber == phase;
lastFrame++);
lastFrame = animation->size(phase);
}
currentFrame = firstFrame;
}
CBattleHero::CBattleHero(const std::string & defName, bool flipG, PlayerColor player, const CGHeroInstance * hero, const CBattleInterface * owner):
CBattleHero::CBattleHero(const std::string & animationPath, bool flipG, PlayerColor player, const CGHeroInstance * hero, const CBattleInterface * owner):
flip(flipG),
myHero(hero),
myOwner(owner),
@ -246,39 +257,25 @@ CBattleHero::CBattleHero(const std::string & defName, bool flipG, PlayerColor pl
flagAnim(0),
animCount(0)
{
dh = CDefHandler::giveDef( defName );
for(auto & elem : dh->ourImages) //transforming images
{
if(flip)
{
SDL_Surface * hlp = CSDL_Ext::verticalFlip(elem.bitmap);
SDL_FreeSurface(elem.bitmap);
elem.bitmap = hlp;
}
CSDL_Ext::alphaTransform(elem.bitmap);
}
animation = std::make_shared<CAnimation>(animationPath);
animation->preload();
if(flipG)
animation->verticalFlip();
if(flip)
flag = CDefHandler::giveDef("CMFLAGR.DEF");
flagAnimation = std::make_shared<CAnimation>("CMFLAGR");
else
flag = CDefHandler::giveDef("CMFLAGL.DEF");
flagAnimation = std::make_shared<CAnimation>("CMFLAGL");
flagAnimation->preload();
flagAnimation->playerColored(player);
//coloring flag and adding transparency
for(auto & elem : flag->ourImages)
{
CSDL_Ext::alphaTransform(elem.bitmap);
graphics->blueToPlayersAdv(elem.bitmap, player);
}
addUsedEvents(LCLICK | RCLICK | HOVER);
switchToNextPhase();
}
CBattleHero::~CBattleHero()
{
delete dh;
delete flag;
}
CBattleHero::~CBattleHero() = default;
CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInterface *owner)
{

@ -14,7 +14,6 @@
#include "../windows/CWindowObject.h"
struct SDL_Surface;
class CDefHandler;
class CGHeroInstance;
class CBattleInterface;
class CPicture;
@ -53,19 +52,24 @@ class CBattleHero : public CIntObject
void switchToNextPhase();
public:
bool flip; //false if it's attacking hero, true otherwise
CDefHandler *dh, *flag; //animation and flag
std::shared_ptr<CAnimation> animation;
std::shared_ptr<CAnimation> flagAnimation;
const CGHeroInstance * myHero; //this animation's hero instance
const CBattleInterface * myOwner; //battle interface to which this animation is assigned
int phase; //stage of animation
int nextPhase; //stage of animation to be set after current phase is fully displayed
int currentFrame, firstFrame, lastFrame; //frame of animation
ui8 flagAnim, animCount; //for flag animation
size_t flagAnim;
ui8 animCount; //for flag animation
void show(SDL_Surface * to) override; //prints next frame of animation to to
void setPhase(int newPhase); //sets phase of hero animation
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override; //call-in
void clickRight(tribool down, bool previousState) override; //call-in
CBattleHero(const std::string &defName, bool filpG, PlayerColor player, const CGHeroInstance *hero, const CBattleInterface *owner);
CBattleHero(const std::string & animationPath, bool filpG, PlayerColor player, const CGHeroInstance * hero, const CBattleInterface * owner);
~CBattleHero();
};

@ -10,14 +10,10 @@
#include "StdInc.h"
#include "CCreatureAnimation.h"
#include "../../lib/vcmi_endian.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/filesystem/CBinaryReader.h"
#include "../../lib/filesystem/CMemoryStream.h"
#include "../gui/SDL_Pixels.h"
#include "../gui/SDL_Extensions.h"
static const SDL_Color creatureBlueBorder = { 0, 255, 255, 255 };
static const SDL_Color creatureGoldBorder = { 255, 255, 0, 255 };
@ -142,60 +138,43 @@ void CCreatureAnimation::setType(CCreatureAnim::EAnimType type)
play();
}
CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController controller)
: defName(name),
speed(0.1),
currentFrame(0),
elapsedTime(0),
CCreatureAnimation::CCreatureAnimation(const std::string & name_, TSpeedController controller)
: name(name_),
speed(0.1),
currentFrame(0),
elapsedTime(0),
type(CCreatureAnim::HOLDING),
border(CSDL_Ext::makeColor(0, 0, 0, 0)),
speedController(controller),
once(false)
speedController(controller),
once(false)
{
// separate block to avoid accidental use of "data" after it was moved into "pixelData"
{
ResourceID resID(std::string("SPRITES/") + name, EResType::ANIMATION);
forward = std::make_shared<CAnimation>(name_);
reverse = std::make_shared<CAnimation>(name_);
auto data = CResourceHandler::get()->load(resID)->readAll();
pixelData = std::move(data.first);
pixelDataSize = data.second;
}
CMemoryStream stm(pixelData.get(), pixelDataSize);
CBinaryReader reader(&stm);
reader.readInt32(); // def type, unused
fullWidth = reader.readInt32();
fullHeight = reader.readInt32();
int totalBlocks = reader.readInt32();
for (auto & elem : palette)
{
elem.r = reader.readUInt8();
elem.g = reader.readUInt8();
elem.b = reader.readUInt8();
elem.a = SDL_ALPHA_OPAQUE;
}
for (int i=0; i<totalBlocks; i++)
{
int groupID = reader.readInt32();
int totalInBlock = reader.readInt32();
reader.skip(4 + 4 + 13 * totalInBlock); // some unused data
for (int j=0; j<totalInBlock; j++)
dataOffsets[groupID].push_back(reader.readUInt32());
}
//todo: optimize
forward->preload();
reverse->preload();
// if necessary, add one frame into vcmi-only group DEAD
if (dataOffsets.count(CCreatureAnim::DEAD) == 0)
dataOffsets[CCreatureAnim::DEAD].push_back(dataOffsets[CCreatureAnim::DEATH].back());
if(forward->size(CCreatureAnim::DEAD) == 0)
{
forward->duplicateImage(CCreatureAnim::DEATH, forward->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD);
reverse->duplicateImage(CCreatureAnim::DEATH, reverse->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD);
}
//TODO: get dimensions form CAnimation
IImage * first = forward->getImage(0, type, true);
if(!first)
{
fullWidth = 0;
fullHeight = 0;
return;
}
fullWidth = first->width();
fullHeight = first->height();
reverse->verticalFlip();
play();
}
@ -285,142 +264,35 @@ static SDL_Color addColors(const SDL_Color & base, const SDL_Color & over)
);
}
std::array<SDL_Color, 8> CCreatureAnimation::genSpecialPalette()
void CCreatureAnimation::genBorderPalette(IImage::BorderPallete & target)
{
std::array<SDL_Color, 8> ret;
ret[0] = genShadow(0);
ret[1] = genShadow(64);
ret[2] = genShadow(128);//unused
ret[3] = genShadow(128);//unused
ret[4] = genShadow(128);
ret[5] = genBorderColor(getBorderStrength(elapsedTime), border);
ret[6] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border));
ret[7] = addColors(genShadow(64), genBorderColor(getBorderStrength(elapsedTime), border));
return ret;
}
template<int bpp>
void CCreatureAnimation::nextFrameT(SDL_Surface * dest, bool rotate)
{
assert(dataOffsets.count(type) && dataOffsets.at(type).size() > size_t(currentFrame));
ui32 offset = dataOffsets.at(type).at(floor(currentFrame));
CMemoryStream stm(pixelData.get(), pixelDataSize);
CBinaryReader reader(&stm);
reader.getStream()->seek(offset);
reader.readUInt32(); // unused, size of pixel data for this frame
const ui32 defType2 = reader.readUInt32();
const ui32 fullWidth = reader.readUInt32();
/*const ui32 fullHeight =*/ reader.readUInt32();
const ui32 spriteWidth = reader.readUInt32();
const ui32 spriteHeight = reader.readUInt32();
const int leftMargin = reader.readInt32();
const int topMargin = reader.readInt32();
const int rightMargin = fullWidth - spriteWidth - leftMargin;
//const int bottomMargin = fullHeight - spriteHeight - topMargin;
const size_t baseOffset = reader.getStream()->tell();
assert(defType2 == 1);
UNUSED(defType2);
auto specialPalette = genSpecialPalette();
for (ui32 i=0; i<spriteHeight; i++)
{
//NOTE: if this loop will be optimized to skip empty lines - recheck this read access
ui8 * lineData = pixelData.get() + baseOffset + reader.readUInt32();
size_t destX = pos.x;
if (rotate)
destX += rightMargin + spriteWidth - 1;
else
destX += leftMargin;
size_t destY = pos.y + topMargin + i;
size_t currentOffset = 0;
size_t totalRowLength = 0;
while (totalRowLength < spriteWidth)
{
ui8 type = lineData[currentOffset++];
ui32 length = lineData[currentOffset++] + 1;
if (type==0xFF)//Raw data
{
for (size_t j=0; j<length; j++)
putPixelAt<bpp>(dest, destX + (rotate?(-j):(j)), destY, lineData[currentOffset + j], specialPalette);
currentOffset += length;
}
else// RLE
{
if (type != 0) // transparency row, handle it here for speed
{
for (size_t j=0; j<length; j++)
putPixelAt<bpp>(dest, destX + (rotate?(-j):(j)), destY, type, specialPalette);
}
}
destX += rotate ? (-length) : (length);
totalRowLength += length;
}
}
target[0] = genBorderColor(getBorderStrength(elapsedTime), border);
target[1] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border));
target[2] = addColors(genShadow(64), genBorderColor(getBorderStrength(elapsedTime), border));
}
void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker)
{
// Note: please notice that attacker value is inversed when passed further.
// This is intended behavior because "attacker" actually does not needs rotation
switch(dest->format->BytesPerPixel)
{
case 2: return nextFrameT<2>(dest, !attacker);
case 3: return nextFrameT<3>(dest, !attacker);
case 4: return nextFrameT<4>(dest, !attacker);
default:
logGlobal->error("%d bpp is not supported!", (int)dest->format->BitsPerPixel);
}
size_t frame = floor(currentFrame);
IImage * image = nullptr;
if(attacker)
image = forward->getImage(frame, type);
else
image = reverse->getImage(frame, type);
IImage::BorderPallete borderPallete;
genBorderPalette(borderPallete);
image->setBorderPallete(borderPallete);
image->draw(dest, pos.x, pos.y);
}
int CCreatureAnimation::framesInGroup(CCreatureAnim::EAnimType group) const
{
if(dataOffsets.count(group) == 0)
return 0;
return dataOffsets.at(group).size();
}
ui8 * CCreatureAnimation::getPixelAddr(SDL_Surface * dest, int X, int Y) const
{
return (ui8*)dest->pixels + X * dest->format->BytesPerPixel + Y * dest->pitch;
}
template<int bpp>
inline void CCreatureAnimation::putPixelAt(SDL_Surface * dest, int X, int Y, size_t index, const std::array<SDL_Color, 8> & special) const
{
if ( X < pos.x + pos.w && Y < pos.y + pos.h && X >= 0 && Y >= 0)
putPixel<bpp>(getPixelAddr(dest, X, Y), palette[index], index, special);
}
template<int bpp>
inline void CCreatureAnimation::putPixel(ui8 * dest, const SDL_Color & color, size_t index, const std::array<SDL_Color, 8> & special) const
{
if((index <= 1) || (index >=4 && index < 8))
{
const SDL_Color & pal = special[index];
ColorPutter<bpp, 0>::PutColor(dest, pal.r, pal.g, pal.b, pal.a);
}
else
{
ColorPutter<bpp, 0>::PutColor(dest, color.r, color.g, color.b);
}
return forward->size(group);
}
bool CCreatureAnimation::isDead() const
@ -456,7 +328,8 @@ void CCreatureAnimation::pause()
void CCreatureAnimation::play()
{
//logAnim->trace("Play %s group %d at %d:%d", name, static_cast<int>(getType()), pos.x, pos.y);
speed = 0;
if (speedController(this, type) != 0)
if(speedController(this, type) != 0)
speed = 1 / speedController(this, type);
}

@ -10,8 +10,8 @@
#pragma once
#include "../../lib/FunctionList.h"
#include "../gui/SDL_Extensions.h"
#include "../widgets/Images.h"
#include "../gui/CAnimation.h"
class CIntObject;
class CCreatureAnimation;
@ -52,21 +52,12 @@ public:
typedef std::function<float(CCreatureAnimation *, size_t)> TSpeedController;
private:
std::string defName;
std::string name;
std::shared_ptr<CAnimation> forward;
std::shared_ptr<CAnimation> reverse;
int fullWidth, fullHeight;
// palette, as read from def file
std::array<SDL_Color, 256> palette;
//key = id of group (note that some groups may be missing)
//value = offset of pixel data for each frame, vector size = number of frames in group
std::map<int, std::vector<unsigned int>> dataOffsets;
//animation raw data
//TODO: use vector instead?
std::unique_ptr<ui8[]> pixelData;
size_t pixelDataSize;
int fullWidth;
int fullHeight;
// speed of animation, measure in frames per second
float speed;
@ -85,21 +76,10 @@ private:
bool once; // animation will be played once and the reset to idling
ui8 * getPixelAddr(SDL_Surface * dest, int ftcpX, int ftcpY) const;
template<int bpp>
void putPixelAt(SDL_Surface * dest, int X, int Y, size_t index, const std::array<SDL_Color, 8> & special) const;
template<int bpp>
void putPixel( ui8 * dest, const SDL_Color & color, size_t index, const std::array<SDL_Color, 8> & special) const;
template<int bpp>
void nextFrameT(SDL_Surface * dest, bool rotate);
void endAnimation();
/// creates 8 special colors for current frame
std::array<SDL_Color, 8> genSpecialPalette();
void genBorderPalette(IImage::BorderPallete & target);
public:
// function(s) that will be called when animation ends, after reset to 1st frame
@ -113,12 +93,12 @@ public:
/// name - path to .def file, relative to SPRITES/ directory
/// controller - function that will return for how long *each* frame
/// in specified group of animation should be played, measured in seconds
CCreatureAnimation(std::string name, TSpeedController speedController);
CCreatureAnimation(const std::string & name_, TSpeedController speedController);
void setType(CCreatureAnim::EAnimType type); //sets type of animation and cleares framecount
CCreatureAnim::EAnimType getType() const; //returns type of animation
void nextFrame(SDL_Surface * dest, bool rotate);
void nextFrame(SDL_Surface * dest, bool attacker);
// should be called every frame, return true when animation was reset to beginning
bool incrementFrame(float timePassed);

@ -29,7 +29,7 @@ typedef std::map <size_t, std::vector <JsonNode> > source_map;
typedef std::map<size_t, IImage* > image_map;
typedef std::map<size_t, image_map > group_map;
/// Class for def loading, methods are based on CDefHandler
/// Class for def loading
/// After loading will store general info (palette and frame offsets) and pointer to file itself
class CDefFile
{
@ -100,6 +100,8 @@ public:
void shiftPalette(int from, int howMany) override;
void setBorderPallete(const BorderPallete & borderPallete) override;
friend class SDLImageLoader;
};
@ -157,6 +159,7 @@ public:
void verticalFlip() override;
void shiftPalette(int from, int howMany) override;
void setBorderPallete(const BorderPallete & borderPallete) override;
friend class CompImageLoader;
};
@ -985,6 +988,15 @@ void SDLImage::shiftPalette(int from, int howMany)
}
}
void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
{
if(surf->format->palette)
{
SDL_SetColors(surf, const_cast<SDL_Color *>(borderPallete.data()), 5, 3);
}
}
SDLImage::~SDLImage()
{
SDL_FreeSurface(surf);
@ -1238,22 +1250,27 @@ CompImage::~CompImage()
void CompImage::horizontalFlip()
{
logAnim->error("CompImage::horizontalFlip is not implemented");
logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
}
void CompImage::verticalFlip()
{
logAnim->error("CompImage::verticalFlip is not implemented");
logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
}
void CompImage::shiftPalette(int from, int howMany)
{
logAnim->error("CompImage::shiftPalette is not implemented");
logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
}
void CompImage::exportBitmap(const boost::filesystem::path& path) const
void CompImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
{
logAnim->error("CompImage::exportBitmap is not implemented");
logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
}
void CompImage::exportBitmap(const boost::filesystem::path & path) const
{
logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
}
@ -1605,6 +1622,38 @@ size_t CAnimation::size(size_t group) const
return 0;
}
void CAnimation::horizontalFlip()
{
for(auto & group : images)
for(auto & image : group.second)
image.second->horizontalFlip();
}
void CAnimation::verticalFlip()
{
for(auto & group : images)
for(auto & image : group.second)
image.second->verticalFlip();
}
void CAnimation::playerColored(PlayerColor player)
{
for(auto & group : images)
for(auto & image : group.second)
image.second->playerColored(player);
}
void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targetGroup)
{
for(size_t frame = 0; frame < size(sourceGroup); ++frame)
{
duplicateImage(sourceGroup, frame, targetGroup);
IImage * image = getImage(frame, targetGroup);
image->verticalFlip();
}
}
float CFadeAnimation::initialCounter() const
{
if (fadingMode == EMode::OUT)

@ -24,6 +24,7 @@ class IImage
{
int refCount;
public:
using BorderPallete = std::array<SDL_Color, 3>;
//draws image on surface "where" at position
virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, Rect * src = nullptr, ui8 alpha = 255) const=0;
@ -49,6 +50,9 @@ public:
//only indexed bitmaps, 16 colors maximum
virtual void shiftPalette(int from, int howMany) = 0;
//only indexed bitmaps, colors 5,6,7 must be special
virtual void setBorderPallete(const BorderPallete & borderPallete) = 0;
virtual void horizontalFlip() = 0;
virtual void verticalFlip() = 0;
@ -127,6 +131,12 @@ public:
//total count of frames in group (including not loaded)
size_t size(size_t group=0) const;
void horizontalFlip();
void verticalFlip();
void playerColored(PlayerColor player);
void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup);
};
const float DEFAULT_DELTA = 0.05f;

@ -23,11 +23,20 @@ void CCursorHandler::initCursor()
xpos = ypos = 0;
type = ECursor::DEFAULT;
dndObject = nullptr;
currentCursor = nullptr;
cursors =
{
make_unique<CAnimImage>("CRADVNTR", 0),
make_unique<CAnimImage>("CRCOMBAT", 0),
make_unique<CAnimImage>("CRDEFLT", 0),
make_unique<CAnimImage>("CRSPELL", 0)
};
currentCursor = cursors.at(int(ECursor::DEFAULT)).get();
help = CSDL_Ext::newSurface(40,40);
//No blending. Ensure, that we are copying pixels during "screen restore draw"
SDL_SetSurfaceBlendMode(help,SDL_BLENDMODE_NONE);
SDL_SetSurfaceBlendMode(help,SDL_BLENDMODE_NONE);
SDL_ShowCursor(SDL_DISABLE);
changeGraphic(ECursor::ADVENTURE, 0);
@ -35,32 +44,23 @@ void CCursorHandler::initCursor()
void CCursorHandler::changeGraphic(ECursor::ECursorTypes type, int index)
{
std::string cursorDefs[4] = { "CRADVNTR.DEF", "CRCOMBAT.DEF", "CRDEFLT.DEF", "CRSPELL.DEF" };
if (type != this->type)
if(type != this->type)
{
BLOCK_CAPTURING; // not used here
this->type = type;
this->frame = index;
delete currentCursor;
currentCursor = new CAnimImage(cursorDefs[int(type)], index);
currentCursor = cursors.at(int(type)).get();
currentCursor->setFrame(index);
}
if (frame != index)
else if(index != this->frame)
{
frame = index;
this->frame = index;
currentCursor->setFrame(index);
}
}
void CCursorHandler::dragAndDropCursor(CAnimImage * object)
void CCursorHandler::dragAndDropCursor(std::unique_ptr<CAnimImage> object)
{
if (dndObject)
delete dndObject;
dndObject = object;
dndObject = std::move(object);
}
void CCursorHandler::cursorMove(const int & x, const int & y)
@ -101,13 +101,6 @@ void CCursorHandler::drawRestored()
SDL_Rect temp_rect = genRect(40, 40, x, y);
SDL_BlitSurface(help, nullptr, screen, &temp_rect);
//blitAt(help,x,y);
}
void CCursorHandler::draw(SDL_Surface *to)
{
currentCursor->moveTo(Point(xpos, ypos));
currentCursor->showAll(screen);
}
void CCursorHandler::shiftPos( int &x, int &y )
@ -233,12 +226,10 @@ void CCursorHandler::render()
drawRestored();
}
CCursorHandler::CCursorHandler() = default;
CCursorHandler::~CCursorHandler()
{
if(help)
SDL_FreeSurface(help);
delete currentCursor;
delete dndObject;
}

@ -17,27 +17,28 @@ namespace ECursor
enum ECursorTypes { ADVENTURE, COMBAT, DEFAULT, SPELLBOOK };
enum EBattleCursors { COMBAT_BLOCKED, COMBAT_MOVE, COMBAT_FLY, COMBAT_SHOOT,
COMBAT_HERO, COMBAT_QUERY, COMBAT_POINTER,
COMBAT_HERO, COMBAT_QUERY, COMBAT_POINTER,
//various attack frames
COMBAT_SHOOT_PENALTY = 15, COMBAT_SHOOT_CATAPULT, COMBAT_HEAL,
COMBAT_SACRIFICE, COMBAT_TELEPORT};
}
/// handles mouse cursor
class CCursorHandler
class CCursorHandler final
{
SDL_Surface * help;
CAnimImage * currentCursor;
CAnimImage * dndObject; //if set, overrides currentCursor
std::unique_ptr<CAnimImage> dndObject; //if set, overrides currentCursor
std::array<std::unique_ptr<CAnimImage>, 4> cursors;
bool showing;
/// Draw cursor preserving original image below cursor
void drawWithScreenRestore();
/// Restore original image below cursor
void drawRestored();
/// Simple draw cursor
void draw(SDL_Surface *to);
public:
/// position of cursor
int xpos, ypos;
@ -58,8 +59,8 @@ public:
* @param image Image to replace cursor with or nullptr to use the normal
* cursor. CursorHandler takes ownership of object
*/
void dragAndDropCursor (CAnimImage * image);
void dragAndDropCursor (std::unique_ptr<CAnimImage> image);
void render();
void shiftPos( int &x, int &y );
@ -71,5 +72,6 @@ public:
/// Move cursor to screen center
void centerCursor();
CCursorHandler();
~CCursorHandler();
};

@ -459,8 +459,7 @@ void CGuiHandler::renderFrame()
// draw the mouse cursor and update the screen
CCS->curh->render();
if(0 != SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr))
logGlobal->error("%s SDL_RenderCopy %s", __FUNCTION__, SDL_GetError());
SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr);
SDL_RenderPresent(mainRenderer);
}

@ -290,7 +290,7 @@ void CHeroArtPlace::select ()
}
}
CCS->curh->dragAndDropCursor(new CAnimImage("artifact", ourArt->artType->iconIndex));
CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", ourArt->artType->iconIndex));
ourOwner->commonInfo->src.setTo(this, false);
ourOwner->markPossibleSlots(ourArt);
@ -766,7 +766,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
commonInfo->src.art = dst.getArt();
commonInfo->src.slotID = dst.slot;
assert(commonInfo->src.AOH);
CCS->curh->dragAndDropCursor(new CAnimImage("artifact", dst.getArt()->artType->iconIndex));
CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", dst.getArt()->artType->iconIndex));
markPossibleSlots(dst.getArt());
}
}

@ -24,6 +24,7 @@
#include "../gui/SDL_Extensions.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CAnimation.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
@ -107,7 +108,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
quitButton = new CButton(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [&](){ close(); }, SDLK_RETURN);
quitButton->assignedKeys.insert(SDLK_ESCAPE);
dismissButton = new CButton(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [&](){ dismissCurrent(); }, SDLK_d);
questlogButton = new CButton(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [&](){ questlog(); }, SDLK_q);
questlogButton = new CButton(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, SDLK_q);
formations = new CToggleGroup(0);
formations->addToggle(0, new CToggleButton(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, SDLK_t));
@ -144,11 +145,12 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
luck = new MoraleLuckBox(false, Rect(233,179,53,45));
spellPointsArea = new LRClickableAreaWText(Rect(162,228, 136, 42), CGI->generaltexth->heroscrn[22]);
auto secSkills = std::make_shared<CAnimation>("SECSKILL");
for(int i = 0; i < std::min<size_t>(hero->secSkills.size(), 8u); ++i)
{
Rect r = Rect(i%2 == 0 ? 18 : 162, 276 + 48 * (i/2), 136, 42);
secSkillAreas.push_back(new LRClickableAreaWTextComp(r, CComponent::secskill));
secSkillImages.push_back(new CAnimImage("SECSKILL", 0, 0, r.x, r.y));
secSkillImages.push_back(new CAnimImage(secSkills, 0, 0, r.x, r.y));
}
//dismiss / quest log
@ -158,12 +160,14 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
//////////////////////////////////////////////////////////////////////////???????????????
//primary skills & exp and mana
new CAnimImage("PSKIL42", 0, 0, 32, 111, false);
new CAnimImage("PSKIL42", 1, 0, 102, 111, false);
new CAnimImage("PSKIL42", 2, 0, 172, 111, false);
new CAnimImage("PSKIL42", 3, 0, 162, 230, false);
new CAnimImage("PSKIL42", 4, 0, 20, 230, false);
new CAnimImage("PSKIL42", 5, 0, 242, 111, false);
auto primSkills = std::make_shared<CAnimation>("PSKIL42");
primSkills->preload();
new CAnimImage(primSkills, 0, 0, 32, 111);
new CAnimImage(primSkills, 1, 0, 102, 111);
new CAnimImage(primSkills, 2, 0, 172, 111);
new CAnimImage(primSkills, 3, 0, 162, 230);
new CAnimImage(primSkills, 4, 0, 20, 230);
new CAnimImage(primSkills, 5, 0, 242, 111);
// various texts
new CLabel( 52, 99, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->jktexts[1]);
@ -306,11 +310,6 @@ void CHeroWindow::dismissCurrent()
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[22], ony, 0, false);
}
void CHeroWindow::questlog()
{
LOCPLINT->showQuestLog();
}
void CHeroWindow::commanderWindow()
{
//TODO: allow equipping commander artifacts by drag / drop

@ -86,7 +86,6 @@ public:
void showAll(SDL_Surface * to) override;
void dismissCurrent(); //dissmissed currently displayed hero (curHero)
void questlog(); //show quest log in hero window
void commanderWindow();
void switchHero(); //changes displayed hero
virtual void updateGarrisons() override; //updates the morale widget and calls the parent

@ -187,7 +187,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
aw->arts->markPossibleSlots(art);
//aw->arts->commonInfo->dst.AOH = aw->arts;
CCS->curh->dragAndDropCursor(new CAnimImage("artifact", art->artType->iconIndex));
CCS->curh->dragAndDropCursor(make_unique<CAnimImage>("artifact", art->artType->iconIndex));
aw->arts->artifactsOnAltar.erase(art);
setID(-1);

@ -37,7 +37,6 @@ class CGObjectInstance;
class CCreature;
class CMap;
struct StartInfo;
struct SDL_Surface;
class CMapHandler;
struct SetObjectProperty;
struct MetaString;