summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-10-01 17:59:04 +0200
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-10-08 21:01:45 +0200
commit59a7d5c58f8b3af21b3e19d4e78f5653bf011bfb (patch)
tree536f6b80e359922172e671fbbbeb2b7bc5d3f165 /src/gui
parente115390f18734d9e3e0e2fc5e1ed05f44c9fdb60 (diff)
downloadmana-59a7d5c58f8b3af21b3e19d4e78f5653bf011bfb.tar.gz
mana-59a7d5c58f8b3af21b3e19d4e78f5653bf011bfb.tar.bz2
mana-59a7d5c58f8b3af21b3e19d4e78f5653bf011bfb.tar.xz
mana-59a7d5c58f8b3af21b3e19d4e78f5653bf011bfb.zip
Added convenient and efficient Timer class
The Timer is efficient because it does not depend on incrementing a counter to keep track of time, nor does it call SDL_GetTicks every time its state is checked (this happens once per frame instead). Along with global functions Time::absoluteTimeMs() and Time::deltaTimeMs(), this replaces previous globals tick_time, cur_time and get_elapsed_time(). For now, there is still a fixed 100 times per second logic call rate, but the new Time::deltaTimeMs() function should allow getting rid of this.
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/gui.cpp4
-rw-r--r--src/gui/gui.h4
-rw-r--r--src/gui/ministatuswindow.cpp5
-rw-r--r--src/gui/palette.cpp146
-rw-r--r--src/gui/palette.h10
-rw-r--r--src/gui/socialwindow.cpp6
-rw-r--r--src/gui/socialwindow.h4
-rw-r--r--src/gui/viewport.cpp100
-rw-r--r--src/gui/viewport.h8
-rw-r--r--src/gui/widgets/browserbox.cpp8
-rw-r--r--src/gui/widgets/browserbox.h4
11 files changed, 145 insertions, 154 deletions
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 26d0913e..2ff697c7 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -158,7 +158,7 @@ Gui::~Gui()
void Gui::logic()
{
// Hide mouse cursor after extended inactivity
- if (get_elapsed_time(mLastMouseActivityTime) > 15000)
+ if (mMouseActivityTimer.passed())
SDL_ShowCursor(SDL_DISABLE);
Palette::advanceGradients();
@@ -239,7 +239,7 @@ void Gui::updateCursor()
void Gui::handleMouseMoved(const gcn::MouseInput &mouseInput)
{
gcn::Gui::handleMouseMoved(mouseInput);
- mLastMouseActivityTime = tick_time;
+ mMouseActivityTimer.set(15000);
// Make sure the cursor is visible
SDL_ShowCursor(SDL_ENABLE);
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 7c3c3afd..fd1dcf94 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -25,6 +25,8 @@
#include "eventlistener.h"
#include "guichanfwd.h"
+#include "utils/time.h"
+
#include <guichan/gui.hpp>
#include <SDL.h>
@@ -137,7 +139,7 @@ class Gui final : public gcn::Gui, public EventListener
float mCustomCursorScale = 1.0f;
std::vector<SDL_Cursor *> mSystemMouseCursors;
std::vector<SDL_Cursor *> mCustomMouseCursors;
- int mLastMouseActivityTime = 0;
+ Timer mMouseActivityTimer;
Cursor mCursorType = Cursor::POINTER;
};
diff --git a/src/gui/ministatuswindow.cpp b/src/gui/ministatuswindow.cpp
index d3e01bd2..e22172bc 100644
--- a/src/gui/ministatuswindow.cpp
+++ b/src/gui/ministatuswindow.cpp
@@ -43,8 +43,7 @@
#include "utils/gettext.h"
#include "utils/stringutils.h"
-
-extern volatile int tick_time;
+#include "utils/time.h"
MiniStatusWindow::MiniStatusWindow():
Popup("MiniStatus")
@@ -227,7 +226,7 @@ void MiniStatusWindow::logic()
for (auto &icon : mIcons)
if (icon)
- icon->update(tick_time * 10);
+ icon->update(Time::absoluteTimeMs());
}
void MiniStatusWindow::mouseMoved(gcn::MouseEvent &event)
diff --git a/src/gui/palette.cpp b/src/gui/palette.cpp
index aaa3165c..6c6e6f06 100644
--- a/src/gui/palette.cpp
+++ b/src/gui/palette.cpp
@@ -22,18 +22,11 @@
#include "palette.h"
-#include "configuration.h"
-#include "client.h"
-
-#include "gui/gui.h"
-
-#include "utils/gettext.h"
-#include "utils/stringutils.h"
-
#include <cmath>
-static const double PI = 3.14159265;
+static constexpr double PI = 3.14159265;
const gcn::Color Palette::BLACK = gcn::Color(0, 0, 0);
+Timer Palette::mRainbowTimer;
Palette::Palettes Palette::mInstances;
const gcn::Color Palette::RAINBOW_COLORS[7] = {
@@ -49,7 +42,6 @@ const gcn::Color Palette::RAINBOW_COLORS[7] = {
const int Palette::RAINBOW_COLOR_COUNT = 7;
Palette::Palette(int size) :
- mRainbowTime(tick_time),
mColors(size)
{
mInstances.insert(this);
@@ -76,97 +68,85 @@ const gcn::Color &Palette::getColor(char c, bool &valid)
void Palette::advanceGradients()
{
- auto it = mInstances.begin();
- auto it_end = mInstances.end();
+ const int advance = mRainbowTimer.elapsed() / 5;
+ if (advance <= 0)
+ return;
- for (; it != it_end; it++)
- {
- (*it)->advanceGradient();
- }
+ mRainbowTimer.extend(advance * 5);
+
+ for (auto palette : mInstances)
+ palette->advanceGradient(advance);
}
-void Palette::advanceGradient()
+void Palette::advanceGradient(int advance)
{
- if (get_elapsed_time(mRainbowTime) > 5)
+ for (auto elem : mGradVector)
{
- int pos, colIndex, colVal, delay, numOfColors;
- // For slower systems, advance can be greater than one (advance > 1
- // skips advance-1 steps). Should make gradient look the same
- // independent of the framerate.
- int advance = get_elapsed_time(mRainbowTime) / 5;
- double startColVal, destColVal;
-
- for (auto &elem : mGradVector)
- {
- delay = elem->delay;
+ int delay = elem->delay;
- if (elem->grad == PULSE)
- delay = delay / 20;
+ if (elem->grad == PULSE)
+ delay = delay / 20;
- numOfColors = (elem->grad == SPECTRUM ? 6 :
- elem->grad == PULSE ? 127 :
- RAINBOW_COLOR_COUNT);
+ const int numOfColors = (elem->grad == SPECTRUM ? 6 :
+ elem->grad == PULSE ? 127 :
+ RAINBOW_COLOR_COUNT);
- elem->gradientIndex =
- (elem->gradientIndex + advance) %
- (delay * numOfColors);
+ elem->gradientIndex = (elem->gradientIndex + advance) %
+ (delay * numOfColors);
- pos = elem->gradientIndex % delay;
- colIndex = elem->gradientIndex / delay;
+ const int pos = elem->gradientIndex % delay;
+ const int colIndex = elem->gradientIndex / delay;
- if (elem->grad == PULSE)
- {
- colVal = (int) (255.0 * sin(PI * colIndex / numOfColors));
+ if (elem->grad == PULSE)
+ {
+ const int colVal = (int) (255.0 * sin(PI * colIndex / numOfColors));
+ const gcn::Color &col = elem->testColor;
- const gcn::Color &col = elem->testColor;
+ elem->color.r = ((colVal * col.r) / 255) % (col.r + 1);
+ elem->color.g = ((colVal * col.g) / 255) % (col.g + 1);
+ elem->color.b = ((colVal * col.b) / 255) % (col.b + 1);
+ }
+ if (elem->grad == SPECTRUM)
+ {
+ int colVal;
- elem->color.r = ((colVal * col.r) / 255) % (col.r + 1);
- elem->color.g = ((colVal * col.g) / 255) % (col.g + 1);
- elem->color.b = ((colVal * col.b) / 255) % (col.b + 1);
+ if (colIndex % 2)
+ { // falling curve
+ colVal = (int)(255.0 * (cos(PI * pos / delay) + 1) / 2);
}
- if (elem->grad == SPECTRUM)
- {
- if (colIndex % 2)
- { // falling curve
- colVal = (int)(255.0 * (cos(PI * pos / delay) + 1) / 2);
- }
- else
- { // ascending curve
- colVal = (int)(255.0 * (cos(PI * (delay - pos) / delay) +
- 1) / 2);
- }
-
- elem->color.r =
- (colIndex == 0 || colIndex == 5) ? 255 :
- (colIndex == 1 || colIndex == 4) ? colVal : 0;
- elem->color.g =
- (colIndex == 1 || colIndex == 2) ? 255 :
- (colIndex == 0 || colIndex == 3) ? colVal : 0;
- elem->color.b =
- (colIndex == 3 || colIndex == 4) ? 255 :
- (colIndex == 2 || colIndex == 5) ? colVal : 0;
+ else
+ { // ascending curve
+ colVal = (int)(255.0 * (cos(PI * (delay - pos) / delay) +
+ 1) / 2);
}
- else if (elem->grad == RAINBOW)
- {
- const gcn::Color &startCol = RAINBOW_COLORS[colIndex];
- const gcn::Color &destCol =
- RAINBOW_COLORS[(colIndex + 1) % numOfColors];
- startColVal = (cos(PI * pos / delay) + 1) / 2;
- destColVal = 1 - startColVal;
+ elem->color.r =
+ (colIndex == 0 || colIndex == 5) ? 255 :
+ (colIndex == 1 || colIndex == 4) ? colVal : 0;
+ elem->color.g =
+ (colIndex == 1 || colIndex == 2) ? 255 :
+ (colIndex == 0 || colIndex == 3) ? colVal : 0;
+ elem->color.b =
+ (colIndex == 3 || colIndex == 4) ? 255 :
+ (colIndex == 2 || colIndex == 5) ? colVal : 0;
+ }
+ else if (elem->grad == RAINBOW)
+ {
+ const gcn::Color &startCol = RAINBOW_COLORS[colIndex];
+ const gcn::Color &destCol =
+ RAINBOW_COLORS[(colIndex + 1) % numOfColors];
- elem->color.r =(int)(startColVal * startCol.r +
- destColVal * destCol.r);
+ const double startColVal = (cos(PI * pos / delay) + 1) / 2;
+ const double destColVal = 1 - startColVal;
- elem->color.g =(int)(startColVal * startCol.g +
- destColVal * destCol.g);
+ elem->color.r =(int)(startColVal * startCol.r +
+ destColVal * destCol.r);
- elem->color.b =(int)(startColVal * startCol.b +
- destColVal * destCol.b);
- }
- }
+ elem->color.g =(int)(startColVal * startCol.g +
+ destColVal * destCol.g);
- if (advance)
- mRainbowTime = tick_time;
+ elem->color.b =(int)(startColVal * startCol.b +
+ destColVal * destCol.b);
+ }
}
}
diff --git a/src/gui/palette.h b/src/gui/palette.h
index 41378a43..b81d8865 100644
--- a/src/gui/palette.h
+++ b/src/gui/palette.h
@@ -23,6 +23,8 @@
#ifndef PALETTE_H
#define PALETTE_H
+#include "utils/time.h"
+
#include <guichan/color.hpp>
#include <cstdlib>
@@ -121,8 +123,8 @@ class Palette
static const gcn::Color RAINBOW_COLORS[];
static const int RAINBOW_COLOR_COUNT;
- /** Time tick, that gradient-type colors were updated the last time. */
- int mRainbowTime;
+ /** Timer used when updating gradient-type colors. */
+ static Timer mRainbowTimer;
using Palettes = std::set<Palette *>;
static Palettes mInstances;
@@ -131,7 +133,7 @@ class Palette
~Palette();
- void advanceGradient();
+ void advanceGradient(int advance);
struct ColorElem
{
@@ -147,7 +149,7 @@ class Palette
int delay;
int committedDelay;
- void set(int type, gcn::Color &color, GradientType grad, int delay)
+ void set(int type, const gcn::Color &color, GradientType grad, int delay)
{
ColorElem::type = type;
ColorElem::color = color;
diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp
index 76235306..79a0fd53 100644
--- a/src/gui/socialwindow.cpp
+++ b/src/gui/socialwindow.cpp
@@ -262,7 +262,7 @@ private:
class PlayerListTab : public SocialTab
{
public:
- PlayerListTab()
+ PlayerListTab()
{
mPlayerList = new PlayerList;
@@ -679,10 +679,10 @@ void SocialWindow::setPlayersOnline(const std::vector<Avatar*> &players)
void SocialWindow::logic()
{
- if (mLastOnlineListUpdate == 0 || get_elapsed_time(mLastOnlineListUpdate) >= 18000)
+ if (mOnlineListUpdateTimer.passed())
{
Net::getChatHandler()->requestOnlineList();
- mLastOnlineListUpdate = tick_time;
+ mOnlineListUpdateTimer.set(18000);
}
Window::logic();
diff --git a/src/gui/socialwindow.h b/src/gui/socialwindow.h
index b6865fb2..350f919c 100644
--- a/src/gui/socialwindow.h
+++ b/src/gui/socialwindow.h
@@ -21,6 +21,8 @@
#ifndef SOCIALWINDOW_H
#define SOCIALWINDOW_H
+#include "utils/time.h"
+
#include "gui/widgets/window.h"
#include <guichan/actionevent.hpp>
@@ -87,7 +89,7 @@ protected:
void updateButtons();
int mGuildInvited = 0;
- int mLastOnlineListUpdate = 0;
+ Timer mOnlineListUpdateTimer;
ConfirmDialog *mGuildAcceptDialog = nullptr;
TextDialog *mGuildCreateDialog = nullptr;
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index cdc4076e..8dbdf7c7 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -79,8 +79,6 @@ void Viewport::setMap(Map *map)
void Viewport::draw(gcn::Graphics *gcnGraphics)
{
- static int lastTick = tick_time;
-
// Check whether map was successfully loaded since
// the rest of this function relies on it
if (!mMap || !local_player)
@@ -95,12 +93,6 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
auto *graphics = static_cast<Graphics*>(gcnGraphics);
- // Avoid freaking out when tick_time overflows
- if (tick_time < lastTick)
- {
- lastTick = tick_time;
- }
-
// Calculate viewpoint
int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2;
int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2;
@@ -109,49 +101,57 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
const int player_x = (int) playerPos.x - midTileX;
const int player_y = (int) playerPos.y - midTileY;
- if (mScrollLaziness < 1)
- mScrollLaziness = 1; // Avoids division by zero
+ const float ticks = Time::deltaTimeMs() / static_cast<float>(MILLISECONDS_IN_A_TICK);
+ float scrollFraction = 1.0f;
- while (lastTick < tick_time)
+ if (mScrollLaziness > 1)
{
- // Apply lazy scrolling
- if (player_x > mPixelViewX + mScrollRadius)
- {
- mPixelViewX += (player_x - mPixelViewX - mScrollRadius) /
- mScrollLaziness;
- }
- if (player_x < mPixelViewX - mScrollRadius)
- {
- mPixelViewX += (player_x - mPixelViewX + mScrollRadius) /
- mScrollLaziness;
- }
- if (player_y > mPixelViewY + mScrollRadius)
- {
- mPixelViewY += (player_y - mPixelViewY - mScrollRadius) /
- mScrollLaziness;
- }
- if (player_y < mPixelViewY - mScrollRadius)
- {
- mPixelViewY += (player_y - mPixelViewY + mScrollRadius) /
- mScrollLaziness;
- }
+ // mScrollLaziness defines the fraction of the desired camera movement
+ // that is applied every 10ms. To make this work independently of the
+ // frame duration, we calculate the actual scroll fraction based on the
+ // time delta.
+ scrollFraction = 1.0f - std::pow(1.0f - 1.0f / mScrollLaziness, ticks);
+ }
+
+ // Apply lazy scrolling
+ if (player_x > mPixelViewX + mScrollRadius)
+ {
+ mPixelViewX += (player_x - mPixelViewX - mScrollRadius) *
+ scrollFraction;
+ }
+ if (player_x < mPixelViewX - mScrollRadius)
+ {
+ mPixelViewX += (player_x - mPixelViewX + mScrollRadius) *
+ scrollFraction;
+ }
+ if (player_y > mPixelViewY + mScrollRadius)
+ {
+ mPixelViewY += (player_y - mPixelViewY - mScrollRadius) *
+ scrollFraction;
+ }
+ if (player_y < mPixelViewY - mScrollRadius)
+ {
+ mPixelViewY += (player_y - mPixelViewY + mScrollRadius) *
+ scrollFraction;
+ }
+
+ // manage shake effect
+ for (auto i = mShakeEffects.begin(); i != mShakeEffects.end(); i++)
+ {
+ // The decay defines the reduction in amplitude per 10ms. Here
+ // we calculate the reduction based on the ticks.
+ const float decay = std::pow(i->decay, ticks);
+
+ // apply the effect to viewport
+ mPixelViewX += i->x *= -decay;
+ mPixelViewY += i->y *= -decay;
- // manage shake effect
- for (auto i = mShakeEffects.begin();
- i != mShakeEffects.end();
- i++)
+ // check death conditions
+ if (std::abs(i->x) + std::abs(i->y) < 1.0f ||
+ (i->timer.isSet() && i->timer.passed()))
{
- // apply the effect to viewport
- mPixelViewX += i->x *= -i->decay;
- mPixelViewY += i->y *= -i->decay;
- // check death conditions
- if (abs(i->x) + abs(i->y) < 1.0f ||
- (i->duration > 0 && --i->duration == 0))
- {
- i = mShakeEffects.erase(i);
- }
+ i = mShakeEffects.erase(i);
}
- lastTick++;
}
// Auto center when player is off screen
@@ -264,7 +264,9 @@ void Viewport::shakeScreen(float x, float y, float decay, unsigned duration)
effect.x = x;
effect.y = y;
effect.decay = decay;
- effect.duration = duration;
+
+ if (duration > 0)
+ effect.timer.set(duration * MILLISECONDS_IN_A_TICK);
}
void Viewport::logic()
@@ -528,9 +530,9 @@ void Viewport::mouseDragged(gcn::MouseEvent &event)
if (mPlayerFollowMouse && !event.isShiftPressed())
{
- if (get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
+ if (mLocalWalkTimer.passed())
{
- mLocalWalkTime = tick_time;
+ mLocalWalkTimer.set(walkingMouseDelay);
local_player->setDestination(event.getX() + (int) mPixelViewX,
event.getY() + (int) mPixelViewY);
local_player->pathSetByMouse();
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 32d9bd5c..53edb50f 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -25,6 +25,8 @@
#include "eventlistener.h"
#include "position.h"
+#include "utils/time.h"
+
#include "gui/widgets/windowcontainer.h"
#include <guichan/mouselistener.hpp>
@@ -207,15 +209,15 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
float x;
float y;
float decay;
- unsigned duration;
+ Timer timer;
};
std::list<ShakeEffect> mShakeEffects;
bool mPlayerFollowMouse = false;
- int mLocalWalkTime = -1; /**< Timestamp before the next walk can be sent. */
+ Timer mLocalWalkTimer; /**< Timer for sending walk messages. */
- PopupMenu *mPopupMenu; /**< Popup menu. */
+ PopupMenu *mPopupMenu; /**< Popup menu. */
Being *mHoverBeing = nullptr; /**< Being mouse is currently over. */
FloorItem *mHoverItem = nullptr; /**< FloorItem mouse is currently over. */
BeingPopup *mBeingPopup; /**< Being information popup. */
diff --git a/src/gui/widgets/browserbox.cpp b/src/gui/widgets/browserbox.cpp
index 40c9b66a..9eee9448 100644
--- a/src/gui/widgets/browserbox.cpp
+++ b/src/gui/widgets/browserbox.cpp
@@ -22,8 +22,6 @@
#include "gui/widgets/browserbox.h"
-#include "client.h"
-
#include "gui/gui.h"
#include "gui/truetypefont.h"
#include "gui/widgets/linkhandler.h"
@@ -32,6 +30,8 @@
#include "resources/iteminfo.h"
#include "resources/theme.h"
+#include "utils/stringutils.h"
+
#include <guichan/graphics.hpp>
#include <guichan/font.hpp>
#include <guichan/cliprectangle.hpp>
@@ -276,7 +276,7 @@ void BrowserBox::relayoutText()
layoutTextRow(row, context);
mLastLayoutWidth = getWidth();
- mLastLayoutTime = tick_time;
+ mLayoutTimer.set(100);
setHeight(context.y);
}
@@ -507,7 +507,7 @@ void BrowserBox::maybeRelayoutText()
{
// Reduce relayouting frequency when there is a lot of text
if (mTextRows.size() > 100)
- if (mLastLayoutTime && std::abs(mLastLayoutTime - tick_time) < 10)
+ if (!mLayoutTimer.passed())
return;
relayoutText();
diff --git a/src/gui/widgets/browserbox.h b/src/gui/widgets/browserbox.h
index d7ff0428..7278bb59 100644
--- a/src/gui/widgets/browserbox.h
+++ b/src/gui/widgets/browserbox.h
@@ -23,6 +23,8 @@
#ifndef BROWSERBOX_H
#define BROWSERBOX_H
+#include "utils/time.h"
+
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
@@ -193,7 +195,7 @@ class BrowserBox : public gcn::Widget,
std::optional<BrowserLink> mHoveredLink;
unsigned int mMaxRows = 0;
int mLastLayoutWidth = 0;
- int mLastLayoutTime = -1;
+ Timer mLayoutTimer;
};
#endif