summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-10-11 15:35:15 +0200
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-05-08 14:03:08 +0000
commitda60ed7ed07c2b96f3231a0476014dbbf186843e (patch)
tree17882266cd1abdc64dc78bc7b7724767dc314312
parent3f630c76de06a0cbda163342b5ae0bf166aaad9f (diff)
downloadmana-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.cpp59
-rw-r--r--src/map.h14
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);
}
}
}
diff --git a/src/map.h b/src/map.h
index f3850722..06c593e1 100644
--- a/src/map.h
+++ b/src/map.h
@@ -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;
};