Effect Frame Update Optimization
The frame controller update function, used in mesh and texture effect animations, originally relied on a fixed loop (up to 20 iterations) to simulate the passage of frames based on the accumulated elapsed time. This had several downsides:
Inefficient CPU usage due to repeated branching.
Limited scalability – could miss frames if elapsed time was large.
More complex and harder-to-maintain code.
What's Improved with the Change?
The new logic replaces the loop with a direct calculation.
It computes how many frames should have passed based on the total elapsed time.
All necessary frame advancements are done at once, in a single operation.
Looping behavior and animation end conditions are still handled properly.
Benefits
Lower CPU usage – avoids unnecessary loops and branching.
Scales better – handles large time jumps (e.g., low FPS situations) more smoothly.
Cleaner, more maintainable code.
Summary
This optimization improves CPU efficiency and performance of mesh and texture effect animations during low-FPS situations, resulting in smoother visual effects. It does not guarantee a stable 60 FPS but ensures frame updates are handled more efficiently and responsively.
*Poze / Video:
EffectLib -> FrameController.cpp
*Link download / Code:
Code:
//edit PepsiZero metin2forum
#include "StdAfx.h"
#include "FrameController.h"
void CFrameController::Update(float fElapsedTime)
{
#ifdef ENABLE_EFFECT_UPDATE_OPTIMIZATION
if (!m_isActive)
return;
if (fElapsedTime <= 0.0f)
return;
if (m_fFrameTime <= 0.0f || m_dwMaxFrame == 0)
{
m_iLoopCount = 1;
m_dwcurFrame = 0;
m_fLastFrameTime = 0.0f;
m_isActive = FALSE;
return;
}
m_fLastFrameTime -= fElapsedTime;
if (m_fLastFrameTime >= 0.0f)
return;
double dAdvanceFrame = double(-m_fLastFrameTime) / double(m_fFrameTime);
DWORD dwAdvanceFrame;
if (!(dAdvanceFrame >= 0.0))
{
m_fLastFrameTime = m_fFrameTime;
return;
}
if (dAdvanceFrame >= 4294967295.0)
{
dwAdvanceFrame = 0xffffffff;
m_fLastFrameTime = 0.0f;
}
else
{
dwAdvanceFrame = DWORD(dAdvanceFrame);
double dLastFrameTime = double(m_fLastFrameTime) + double(m_fFrameTime) * double(dwAdvanceFrame);
if (dLastFrameTime < 0.0)
{
dLastFrameTime += double(m_fFrameTime);
++dwAdvanceFrame;
}
m_fLastFrameTime = float(dLastFrameTime);
}
if (dwAdvanceFrame == 0)
return;
if (m_dwcurFrame >= m_dwMaxFrame)
m_dwcurFrame = 0;
if (!m_isLoop)
{
if (dwAdvanceFrame >= m_dwMaxFrame - m_dwcurFrame)
{
m_iLoopCount = 1;
m_dwcurFrame = 0;
m_isActive = FALSE;
return;
}
m_dwcurFrame += dwAdvanceFrame;
return;
}
DWORD dwLoopCount = dwAdvanceFrame / m_dwMaxFrame;
DWORD dwFrame = dwAdvanceFrame % m_dwMaxFrame;
if (dwFrame >= m_dwMaxFrame - m_dwcurFrame)
{
++dwLoopCount;
m_dwcurFrame = dwFrame - (m_dwMaxFrame - m_dwcurFrame);
}
else
{
m_dwcurFrame += dwFrame;
}
if (m_iLoopCount > 0)
{
if (dwLoopCount >= DWORD(m_iLoopCount))
{
m_iLoopCount = 1;
m_dwcurFrame = 0;
m_isActive = FALSE;
return;
}
m_iLoopCount -= dwLoopCount;
}
else
{
m_iLoopCount = 0;
}
#else
m_fLastFrameTime -= fElapsedTime;
for (int i = 0; i < 20; ++i)
{
if (m_fLastFrameTime < 0.0f)
{
m_fLastFrameTime += m_fFrameTime;
++m_dwcurFrame;
if (m_dwcurFrame >= m_dwMaxFrame)
{
if (m_isLoop && --m_iLoopCount!=0)
{
if (m_iLoopCount<0)
m_iLoopCount = 0;
m_dwcurFrame = 0;
}
else
{
m_iLoopCount = 1;
m_dwcurFrame = 0;
m_isActive = FALSE;
return;
}
}
}
else
{
break;
}
}
#endif
}
void CFrameController::SetCurrentFrame(DWORD dwFrame)
{
m_dwcurFrame = dwFrame;
}
BYTE CFrameController::GetCurrentFrame()
{
return m_dwcurFrame;
}
void CFrameController::SetMaxFrame(DWORD dwMaxFrame)
{
m_dwMaxFrame = dwMaxFrame;
}
void CFrameController::SetFrameTime(float fTime)
{
m_fFrameTime = fTime;
m_fLastFrameTime = fTime;
}
void CFrameController::SetStartFrame(DWORD dwStartFrame)
{
m_dwStartFrame = dwStartFrame;
}
void CFrameController::SetLoopFlag(BOOL bFlag)
{
m_isLoop = bFlag;
}
void CFrameController::SetLoopCount(int iLoopCount)
{
m_iLoopCount = iLoopCount;
}
void CFrameController::SetActive(BOOL bFlag)
{
m_isActive = bFlag;
}
BOOL CFrameController::isActive(DWORD dwMainFrame)
{
if (dwMainFrame < m_dwStartFrame)
return FALSE;
return m_isActive;
}
void CFrameController::Clear()
{
m_isActive = TRUE;
m_dwcurFrame = 0;
m_fLastFrameTime = 0.0f;
m_iLoopCount = 0;
}
CFrameController::CFrameController()
{
m_isActive = TRUE;
m_dwcurFrame = 0;
m_fLastFrameTime = 0.0f;
m_iLoopCount = 0;
m_isLoop = FALSE;
m_dwMaxFrame = 0;
m_fFrameTime = 0.0f;
m_dwStartFrame = 0;
}
CFrameController::~CFrameController()
{
}


