diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-10-11 15:35:15 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-05-08 14:03:08 +0000 |
commit | da60ed7ed07c2b96f3231a0476014dbbf186843e (patch) | |
tree | 17882266cd1abdc64dc78bc7b7724767dc314312 | |
parent | 3f630c76de06a0cbda163342b5ae0bf166aaad9f (diff) | |
download | mana-optimize-actor-draw.tar.gz mana-optimize-actor-draw.tar.bz2 mana-optimize-actor-draw.tar.xz mana-optimize-actor-draw.zip |
Only sort and render visible actorsoptimize-actor-draw
Speeds up rendering a lot in case of many offscreen actors, for example
when a heavy particle effect is running somewhere.
-rw-r--r-- | src/map.cpp | 59 | ||||
-rw-r--r-- | src/map.h | 14 |
2 files changed, 50 insertions, 23 deletions
diff --git a/src/map.cpp b/src/map.cpp index 908d6178..2c64d4fb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -112,7 +112,8 @@ void MapLayer::draw(Graphics *graphics, int startX, int startY, int endX, int endY, int scrollX, int scrollY, - const Actors &actors, int debugFlags) const + const std::vector<FringeActor> &actors, + int debugFlags) const { startX -= mX; startY -= mY; @@ -131,16 +132,15 @@ void MapLayer::draw(Graphics *graphics, for (int y = startY; y < endY; y++) { - int pixelY = y * mMap->getTileHeight(); + const int pixelY = y * mMap->getTileHeight(); // If drawing the fringe layer, make sure all actors above this row of // tiles have been drawn if (mIsFringeLayer) { - while (ai != actors.end() && (*ai)->getDrawOrder() - <= y * mMap->getTileHeight()) + while (ai != actors.end() && ai->drawOrder <= pixelY) { - (*ai)->draw(graphics, -scrollX, -scrollY); + ai->actor->draw(graphics, -scrollX, -scrollY); ++ai; } } @@ -151,8 +151,7 @@ void MapLayer::draw(Graphics *graphics, for (int x = startX; x < endX; x++) { - Image *img = getTile(x, y); - if (img) + if (Image *img = getTile(x, y)) { const int px = (x * mMap->getTileWidth()) + dx; const int py = py0 - img->getHeight(); @@ -182,7 +181,7 @@ void MapLayer::draw(Graphics *graphics, { for (; ai != actors.end(); ++ai) { - (*ai)->draw(graphics, -scrollX, -scrollY); + ai->actor->draw(graphics, -scrollX, -scrollY); } } } @@ -309,17 +308,33 @@ void Map::update(int dt) void Map::draw(Graphics *graphics, int scrollX, int scrollY) { // Calculate range of tiles which are on-screen - int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1; - endPixelY += mMaxTileHeight - mTileHeight; - int startX = (scrollX - mMaxTileWidth + mTileWidth) / mTileWidth; - int startY = scrollY / mTileHeight; - int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth; - int endY = endPixelY / mTileHeight; + const int endPixelY = graphics->getHeight() + scrollY + mMaxTileHeight - 1; + const int endPixelX = graphics->getWidth() + scrollX + mTileWidth - 1; + const int startX = (scrollX - mMaxTileWidth + mTileWidth) / mTileWidth; + const int startY = scrollY / mTileHeight; + const int endX = endPixelX / mTileWidth; + const int endY = endPixelY / mTileHeight; + + mVisibleActors.clear(); + + for (auto actor : mActors) + { + const auto &pos = actor->getPosition(); + if (pos.x < scrollX || pos.y < scrollY || + pos.x > endPixelX || pos.y > endPixelY) + continue; + + auto &va = mVisibleActors.emplace_back(); + va.drawOrder = actor->getDrawOrder(); + va.actor = actor; + } // Make sure actors are sorted ascending by Y-coordinate // so that they overlap correctly - mActors.sort([] (const Actor *a, const Actor *b) { - return a->getDrawOrder() < b->getDrawOrder(); + std::stable_sort(mVisibleActors.begin(), + mVisibleActors.end(), + [] (const FringeActor &a, const FringeActor &b) { + return a.drawOrder < b.drawOrder; }); // update scrolling of all ambient layers @@ -341,7 +356,7 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) layer->draw(graphics, startX, startY, endX, endY, scrollX, scrollY, - mActors, mDebugFlags); + mVisibleActors, mDebugFlags); if (layer->isFringeLayer() && (mDebugFlags & (DEBUG_SPECIAL2 | DEBUG_SPECIAL3))) @@ -353,14 +368,14 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) { // We draw beings with a lower opacity to make them visible // even when covered by a wall or some other elements... - for (auto actor : mActors) + for (const auto &va : mVisibleActors) { // For now, just draw actors with only one layer. - if (actor->drawnWhenBehind()) + if (va.actor->drawnWhenBehind()) { - actor->setAlpha(0.3f); - actor->draw(graphics, -scrollX, -scrollY); - actor->setAlpha(1.0f); + va.actor->setAlpha(0.3f); + va.actor->draw(graphics, -scrollX, -scrollY); + va.actor->setAlpha(1.0f); } } } @@ -74,6 +74,15 @@ class TileAnimation }; /** + * Small struct to reference visible actors and their draw order. + */ +struct FringeActor +{ + int drawOrder; + Actor *actor; +}; + +/** * A map layer. Stores a grid of tiles and their offset, and implements layer * rendering. */ @@ -120,7 +129,7 @@ class MapLayer int startX, int startY, int endX, int endY, int scrollX, int scrollY, - const Actors &actors, + const std::vector<FringeActor> &actors, int debugFlags) const; bool isFringeLayer() const @@ -418,5 +427,8 @@ class Map : public Properties std::map<int, TileAnimation> mTileAnimations; + // Array of visible actors, reused to reduce allocations + std::vector<FringeActor> mVisibleActors; + int mMask = 1; }; |