Browse Source

Move GetFrameToUseForPlayerRendering to AnimationInfo

pull/1753/head
obligaron 5 years ago committed by Anders Jenbo
parent
commit
3b87433fc2
  1. 40
      Source/engine/animationinfo.cpp
  2. 7
      Source/engine/animationinfo.h
  3. 38
      Source/player.cpp
  4. 6
      Source/player.h
  5. 2
      Source/scrollrt.cpp
  6. 2
      test/animationinfo_test.cpp

40
Source/engine/animationinfo.cpp

@ -5,7 +5,47 @@
*/
#include "animationinfo.h"
#include "appfat.h"
#include "nthread.h"
#include "utils/log.hpp"
namespace devilution {
int AnimationInfo::GetFrameToUseForRendering()
{
// Normal logic is used,
// - if no frame-skipping is required and so we have exactly one Animationframe per GameTick
// or
// - if we load from a savegame where the new variables are not stored (we don't want to break savegame compatiblity because of smoother rendering of one animation)
int relevantAnimationFramesForDistributing = RelevantFramesForDistributing;
if (relevantAnimationFramesForDistributing <= 0)
return CurrentFrame;
if (CurrentFrame > relevantAnimationFramesForDistributing)
return CurrentFrame;
assert(GameTicksSinceSequenceStarted >= 0);
float progressToNextGameTick = gfProgressToNextGameTick;
// we don't use the processed game ticks alone but also the fragtion of the next game tick (if a rendering happens between game ticks). This helps to smooth the animations.
float totalGameTicksForCurrentAnimationSequence = progressToNextGameTick + (float)GameTicksSinceSequenceStarted;
// 1 added for rounding reasons. float to int cast always truncate.
int absoluteAnimationFrame = 1 + (int)(totalGameTicksForCurrentAnimationSequence * GameTickModifier);
if (absoluteAnimationFrame > relevantAnimationFramesForDistributing) {
// this can happen if we are at the last frame and the next game tick is due (nthread_GetProgressToNextGameTick returns 1.0f)
if (absoluteAnimationFrame > (relevantAnimationFramesForDistributing + 1)) {
// we should never have +2 frames even if next game tick is due
Log("GetFrameToUseForRendering: Calculated an invalid Animation Frame (Calculated {} MaxFrame {})", absoluteAnimationFrame, relevantAnimationFramesForDistributing);
}
return relevantAnimationFramesForDistributing;
}
if (absoluteAnimationFrame <= 0) {
Log("GetFrameToUseForRendering: Calculated an invalid Animation Frame (Calculated {})", absoluteAnimationFrame);
return 1;
}
return absoluteAnimationFrame;
}
} // namespace devilution

7
Source/engine/animationinfo.h

@ -34,6 +34,13 @@ public:
* @brief Current frame of animation
*/
int CurrentFrame;
/**
* @brief Calculates the Frame to use for the Animation rendering
* @return The Frame to use for rendering
*/
int GetFrameToUseForRendering();
/*
* @brief Specifies how many animations-fractions are displayed between two gameticks. this can be > 0, if animations are skipped or < 0 if the same animation is shown in multiple times (delay specified).
*/

38
Source/player.cpp

@ -15,7 +15,6 @@
#include "loadsave.h"
#include "minitext.h"
#include "missiles.h"
#include "nthread.h"
#include "options.h"
#include "qol/autopickup.h"
#include "spells.h"
@ -3726,43 +3725,6 @@ void ProcessPlayerAnimation(int pnum)
}
}
int GetFrameToUseForPlayerRendering(const PlayerStruct *pPlayer)
{
// Normal logic is used,
// - if no frame-skipping is required and so we have exactly one Animationframe per GameTick
// or
// - if we load from a savegame where the new variables are not stored (we don't want to break savegame compatiblity because of smoother rendering of one animation)
int relevantAnimationFramesForDistributing = pPlayer->AnimInfo.RelevantFramesForDistributing;
if (relevantAnimationFramesForDistributing <= 0)
return pPlayer->AnimInfo.CurrentFrame;
if (pPlayer->AnimInfo.CurrentFrame > relevantAnimationFramesForDistributing)
return pPlayer->AnimInfo.CurrentFrame;
assert(pPlayer->AnimInfo.GameTicksSinceSequenceStarted >= 0);
float progressToNextGameTick = gfProgressToNextGameTick;
// we don't use the processed game ticks alone but also the fragtion of the next game tick (if a rendering happens between game ticks). This helps to smooth the animations.
float totalGameTicksForCurrentAnimationSequence = progressToNextGameTick + (float)pPlayer->AnimInfo.GameTicksSinceSequenceStarted;
// 1 added for rounding reasons. float to int cast always truncate.
int absoluteAnimationFrame = 1 + (int)(totalGameTicksForCurrentAnimationSequence * pPlayer->AnimInfo.GameTickModifier);
if (absoluteAnimationFrame > relevantAnimationFramesForDistributing) {
// this can happen if we are at the last frame and the next game tick is due (nthread_GetProgressToNextGameTick returns 1.0f)
if (absoluteAnimationFrame > (relevantAnimationFramesForDistributing + 1)) {
// we should never have +2 frames even if next game tick is due
Log("GetFrameToUseForPlayerRendering: Calculated an invalid Animation Frame (Calculated {} MaxFrame {})", absoluteAnimationFrame, relevantAnimationFramesForDistributing);
}
return relevantAnimationFramesForDistributing;
}
if (absoluteAnimationFrame <= 0) {
Log("GetFrameToUseForPlayerRendering: Calculated an invalid Animation Frame (Calculated {})", absoluteAnimationFrame);
return 1;
}
return absoluteAnimationFrame;
}
void ClrPlrPath(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {

6
Source/player.h

@ -415,12 +415,6 @@ enum class AnimationDistributionParams : uint8_t {
void NewPlrAnim(int pnum, BYTE *Peq, int numFrames, int Delay, int width, AnimationDistributionParams params = AnimationDistributionParams::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0);
void SetPlrAnims(int pnum);
void ProcessPlayerAnimation(int pnum);
/**
* @brief Calculates the Frame to use for the Animation rendering
* @param pPlayer Player
* @return The Frame to use for rendering
*/
int GetFrameToUseForPlayerRendering(const PlayerStruct *pPlayer);
void CreatePlayer(int pnum, HeroClass c);
int CalcStatDiff(int pnum);
#ifdef _DEBUG

2
Source/scrollrt.cpp

@ -417,7 +417,7 @@ static void DrawPlayer(const CelOutputBuffer &out, int pnum, int x, int y, int p
PlayerStruct *pPlayer = &plr[pnum];
BYTE *pCelBuff = pPlayer->AnimInfo.pData;
int nCel = GetFrameToUseForPlayerRendering(pPlayer);
int nCel = pPlayer->AnimInfo.GetFrameToUseForRendering();
int nWidth = pPlayer->_pAnimWidth;
if (pCelBuff == nullptr) {

2
test/animationinfo_test.cpp

@ -71,7 +71,7 @@ void RunAnimationTest(int numFrames, int delay, AnimationDistributionParams para
auto renderingData = dynamic_cast<RenderingData *>(x);
if (renderingData != nullptr) {
gfProgressToNextGameTick = renderingData->_fProgressToNextGameTick;
EXPECT_EQ(GetFrameToUseForPlayerRendering(pPlayer), renderingData->_ExpectedRenderingFrame)
EXPECT_EQ(pPlayer->AnimInfo.GetFrameToUseForRendering(), renderingData->_ExpectedRenderingFrame)
<< std::fixed << std::setprecision(2)
<< "ProgressToNextGameTick: " << renderingData->_fProgressToNextGameTick
<< " CurrentFrame: " << pPlayer->AnimInfo.CurrentFrame

Loading…
Cancel
Save