I will explain the problem very briefly: In order to get a color animation, the lerp algorithm must be used to change the colors smoothly, which requires the progress of the animation (std::min)((deltaTime / duration), 1.0f) But there is a problem, that by using this animation technique, it runs during the animation duration, but the progress does not reach 1, so that I can kill the timer to avoid additional cpu consumption.
Note that I am using the Direct2D API and the Win32 API for handling my window class.
Before I show you my code, I'll show you how I update my window which you will see in the following codes:
void Window::CreateTimer(bool update, std::uint16_t frameRate, std::uint64_t timerId)
{
SetTimer(m_Hwnd, timerId, 1000 / frameRate, nullptr);
if (update)
{
HandleTimerEvent([&](const Event& event)
{
InvalidateRect(m_hWnd, nullptr, false);
});
}
}
If the update flag was true, we want to handle WM_TIMER to invalidate the window based on the frame rate, which in our case is 60Hz.
Here's the ColorTransition implementaion:
class Transition
{
protected:
Transition(Window* window, float duration)
: m_Window(window), m_Duration(duration)
{
srand(static_cast<std::uint32_t>(time(nullptr)));
QueryPerformanceFrequency(&m_Frequency);
QueryPerformanceCounter(&m_LastFrameTime);
SetTimerId();
SetFrameRate();
m_Window->CreateTimer(true, m_FrameRate, m_TimerId);
}
public:
virtual void Update() = 0;
public:
void SetLastFrameTime()
{
m_LastFrameTime = m_CurrentTime;
}
void SetTimerId()
{
m_TimerId = static_cast<std::uint32_t>(rand());
}
void SetFrameRate(std::uint32_t frameRate = 60)
{
m_FrameRate = frameRate;
KillTimer(m_Window->GetWindow(), m_TimerId);
m_Window->CreateTimer(true, m_FrameRate, m_TimerId);
}
protected:
float m_Duration;
Window* m_Window;
LARGE_INTEGER m_Frequency, m_LastFrameTime, m_CurrentTime;
std::uint32_t m_FrameRate, m_TimerId;
bool m_IsDone;
};
class ColorTransition : public Transition
{
public:
ColorTransition(Window* window, float duration, D2D1::ColorF start, D2D1::ColorF end)
: Transition(window, duration), m_Start(start), m_End(end), m_Color(start)
{
}
D2D1::ColorF GetColor() const
{
return D2D1::ColorF(
m_Color.r / 255.0f,
m_Color.g / 255.0f,
m_Color.b / 255.0f,
m_Color.a / 255.0f);
}
void Update() override
{
QueryPerformanceCounter(&m_CurrentTime);
float deltaTime = static_cast<float>(m_CurrentTime.QuadPart - m_LastFrameTime.QuadPart) /
static_cast<float>(m_Frequency.QuadPart);
float progress = (std::min)((deltaTime / m_Duration), 1.0f);
m_Color.r = Lerp(m_Color.r, m_End.r, progress);
m_Color.g = Lerp(m_Color.g, m_End.g, progress);
m_Color.b = Lerp(m_Color.b, m_End.b, progress);
m_Color.a = Lerp(m_Color.a, m_End.a, progress);
if (progress >= 1.0f)
{
KillTimer(m_Window->GetWindow(), m_TimerId);
m_IsDone = true;
}
}
float Lerp(float start, float end, float progress)
{
return start + (end - start) * progress;
}
private:
D2D1::ColorF m_Start, m_End, m_Color;
};
main.cpp which includes ColorTransition.h:
ColorTransition transition(&window, 1.0f, D2D1::ColorF(0, 55, 255), D2D1::ColorF(255, 0, 0));
window.HandlePaintEvent[&](const Event& event)
{
ID2D1HwndRenderTarget* renderTarget = event.GetRenderTarget();
ID2D1SolidColorBrush* brush = nullptr;
renderTarget->CreateSolidColorBrush(
transition.GetColor(),
&brush
);
transition.Update();
renderTarget->FillRectangle(
D2D1::RectF(10, 10, 110, 110),
brush
);
transition.SetLastFrameTime();
});
I guess the code is pretty simple to understand, so I won't explain the code And I guess I've provided enough code for you to understand what my problem really is.
What I have tried:
I can use a variable called m_ElapsedTime for example to store the elapsed time since the last frame and check if it is equal to the transition animation which works but stops before the transition is almost complete and I have not been able to find any solution for it. There aren't many details about this kind of animation in my case because I've been researching for a while to find a solution, so I really had to ask a question here. If you know a better algorithm or a solution for it, please help me And please explain why my code doesn't work as I said.