diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-10-01 17:59:04 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-10-08 21:01:45 +0200 |
commit | 59a7d5c58f8b3af21b3e19d4e78f5653bf011bfb (patch) | |
tree | 536f6b80e359922172e671fbbbeb2b7bc5d3f165 /src/gui | |
parent | e115390f18734d9e3e0e2fc5e1ed05f44c9fdb60 (diff) | |
download | mana-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.cpp | 4 | ||||
-rw-r--r-- | src/gui/gui.h | 4 | ||||
-rw-r--r-- | src/gui/ministatuswindow.cpp | 5 | ||||
-rw-r--r-- | src/gui/palette.cpp | 146 | ||||
-rw-r--r-- | src/gui/palette.h | 10 | ||||
-rw-r--r-- | src/gui/socialwindow.cpp | 6 | ||||
-rw-r--r-- | src/gui/socialwindow.h | 4 | ||||
-rw-r--r-- | src/gui/viewport.cpp | 100 | ||||
-rw-r--r-- | src/gui/viewport.h | 8 | ||||
-rw-r--r-- | src/gui/widgets/browserbox.cpp | 8 | ||||
-rw-r--r-- | src/gui/widgets/browserbox.h | 4 |
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 |