From 896d41e4b073046c59933ea8829474bd82b9c506 Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Sat, 31 Dec 2016 22:53:42 +0300
Subject: Improve special layers draw speed in same way like fringe layer.

---
 src/being/localplayer.cpp          | 11 ++++++++++-
 src/gui/popups/popupmenu.cpp       |  1 +
 src/resources/map/map.cpp          |  4 ++++
 src/resources/map/mapitem.h        |  1 +
 src/resources/map/maplayer.cpp     | 25 ++++++++++++++++++++-----
 src/resources/map/speciallayer.cpp | 29 ++++++++++++++++++++++++++++-
 src/resources/map/speciallayer.h   |  5 ++++-
 7 files changed, 68 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/being/localplayer.cpp b/src/being/localplayer.cpp
index 9af1371bf..8bb049489 100644
--- a/src/being/localplayer.cpp
+++ b/src/being/localplayer.cpp
@@ -1811,6 +1811,7 @@ void LocalPlayer::setHome()
             {
                 specialLayer->setTile(CAST_S32(pos.x),
                     CAST_S32(pos.y), MapItemType::EMPTY);
+                specialLayer->updateCache();
             }
 
             pos.x = static_cast<float>(mX);
@@ -1872,6 +1873,7 @@ void LocalPlayer::setHome()
         else
         {
             specialLayer->setTile(mX, mY, MapItemType::EMPTY);
+            specialLayer->updateCache();
             socialWindow->removePortal(mX, mY);
         }
     }
@@ -2083,7 +2085,7 @@ void LocalPlayer::navigateClean()
 
     mNavigatePath.clear();
 
-    const SpecialLayer *const tmpLayer = mMap->getTempLayer();
+    SpecialLayer *const tmpLayer = mMap->getTempLayer();
     if (!tmpLayer)
         return;
 
@@ -2553,6 +2555,7 @@ void LocalPlayer::setRealPos(const int x, const int y)
         return;
 
     SpecialLayer *const layer = mMap->getTempLayer();
+    bool cacheUpdated(false);
     if (layer)
     {
         if ((mCrossX || mCrossY) &&
@@ -2560,6 +2563,8 @@ void LocalPlayer::setRealPos(const int x, const int y)
             layer->getTile(mCrossX, mCrossY)->getType() == MapItemType::CROSS)
         {
             layer->setTile(mCrossX, mCrossY, MapItemType::EMPTY);
+            layer->updateCache();
+            cacheUpdated = true;
         }
 
         if (mShowServerPos)
@@ -2569,7 +2574,11 @@ void LocalPlayer::setRealPos(const int x, const int y)
             if (!mapItem || mapItem->getType() == MapItemType::EMPTY)
             {
                 if (mX != x && mY != y)
+                {
                     layer->setTile(x, y, MapItemType::CROSS);
+                    if (cacheUpdated == false)
+                        layer->updateCache();
+                }
             }
         }
 
diff --git a/src/gui/popups/popupmenu.cpp b/src/gui/popups/popupmenu.cpp
index 4ae0966da..b1efa3593 100644
--- a/src/gui/popups/popupmenu.cpp
+++ b/src/gui/popups/popupmenu.cpp
@@ -1186,6 +1186,7 @@ void PopupMenu::handleLink(const std::string &link,
                     const int y = static_cast<const int>(mMapItem->getY());
                     specialLayer->setTile(x, y,
                         CAST_S32(MapItemType::EMPTY));
+                    specialLayer->updateCache();
                     if (socialWindow)
                         socialWindow->removePortal(x, y);
                     if (isHome && localPlayer)
diff --git a/src/resources/map/map.cpp b/src/resources/map/map.cpp
index 759951bcf..49cb43810 100644
--- a/src/resources/map/map.cpp
+++ b/src/resources/map/map.cpp
@@ -1275,7 +1275,10 @@ void Map::addPortalTile(const std::string &restrict name,
                         const int x, const int y) restrict2
 {
     if (mSpecialLayer)
+    {
         mSpecialLayer->setTile(x, y, new MapItem(type, name, x, y));
+        mSpecialLayer->updateCache();
+    }
 
     mMapPortals.push_back(new MapItem(type, name, x, y));
 }
@@ -1296,6 +1299,7 @@ void Map::updatePortalTile(const std::string &restrict name,
         {
             item = new MapItem(type, name, x, y);
             mSpecialLayer->setTile(x, y, item);
+            mSpecialLayer->updateCache();
         }
     }
     else if (addNew)
diff --git a/src/resources/map/mapitem.h b/src/resources/map/mapitem.h
index 949eae9ea..eeff85f88 100644
--- a/src/resources/map/mapitem.h
+++ b/src/resources/map/mapitem.h
@@ -33,6 +33,7 @@ class MapItem final
     public:
         friend class Map;
         friend class MapLayer;
+        friend class SpecialLayer;
 
         MapItem();
 
diff --git a/src/resources/map/maplayer.cpp b/src/resources/map/maplayer.cpp
index 5239403ed..249e67fdd 100644
--- a/src/resources/map/maplayer.cpp
+++ b/src/resources/map/maplayer.cpp
@@ -402,24 +402,39 @@ void MapLayer::drawSpecialLayer(Graphics *const graphics,
         endX1 = specialWidth;
     if (endX1 < 0)
         endX1 = 0;
-
-    for (int x = startX; x < endX1; x++)
+    int x0 = startX;
+    const MapItem *item0 = mSpecialLayer->mTiles[ptr + startX];
+    if (!item0 || item0->mType == MapItemType::EMPTY)
+    {
+        x0 += mSpecialLayer->mCache[ptr + startX];
+    }
+    for (int x = x0; x < endX1; x++)
     {
         const int px1 = x * mapTileSize - scrollX;
-
-        const MapItem *item = mSpecialLayer->mTiles[ptr + x];
+        const MapItem *const item = mSpecialLayer->mTiles[ptr + x];
         if (item)
         {
             item->draw(graphics, px1, py1,
                 mapTileSize, mapTileSize);
         }
+        x += mSpecialLayer->mCache[ptr + x];
+    }
 
-        item = mTempLayer->mTiles[ptr + x];
+    item0 = mTempLayer->mTiles[ptr + startX];
+    if (!item0 || item0->mType == MapItemType::EMPTY)
+    {
+        x0 += mTempLayer->mCache[ptr + startX];
+    }
+    for (int x = x0; x < endX1; x++)
+    {
+        const int px1 = x * mapTileSize - scrollX;
+        const MapItem *const item = mTempLayer->mTiles[ptr + x];
         if (item)
         {
             item->draw(graphics, px1, py1,
                 mapTileSize, mapTileSize);
         }
+        x += mSpecialLayer->mCache[ptr + x];
     }
 }
 
diff --git a/src/resources/map/speciallayer.cpp b/src/resources/map/speciallayer.cpp
index c1ca865d0..b19e665f1 100644
--- a/src/resources/map/speciallayer.cpp
+++ b/src/resources/map/speciallayer.cpp
@@ -36,6 +36,7 @@ SpecialLayer::SpecialLayer(const std::string &name,
     MemoryCounter(),
     mName(name),
     mTiles(new MapItem*[width * height]),
+    mCache(new int[width * height]),
     mWidth(width),
     mHeight(height)
 {
@@ -47,6 +48,7 @@ SpecialLayer::~SpecialLayer()
     for (int f = 0; f < mWidth * mHeight; f ++)
         delete2(mTiles[f])
     delete [] mTiles;
+    delete [] mCache;
 }
 
 MapItem* SpecialLayer::getTile(const int x, const int y) const
@@ -107,9 +109,10 @@ void SpecialLayer::addRoad(const Path &road)
         else
             item->setType(MapItemType::ROAD);
     }
+    updateCache();
 }
 
-void SpecialLayer::clean() const
+void SpecialLayer::clean()
 {
     if (!mTiles)
         return;
@@ -120,6 +123,7 @@ void SpecialLayer::clean() const
         if (item)
             item->setType(MapItemType::EMPTY);
     }
+    updateCache();
 }
 
 void SpecialLayer::draw(Graphics *const graphics, int startX, int startY,
@@ -158,3 +162,26 @@ int SpecialLayer::calcMemoryLocal() const
     return static_cast<int>(sizeof(SpecialLayer) +
         sizeof(MapItem) * mWidth * mHeight);
 }
+
+void SpecialLayer::updateCache()
+{
+    for (int y = 0; y < mHeight; y ++)
+    {
+        const int y2 = y * mWidth;
+        for (int x = 0; x < mWidth; x ++)
+        {
+            int c = 10000;
+            for (int f = x + 1; f < mWidth; f ++)
+            {
+                MapItem *const item = mTiles[f + y2];
+                if (item != nullptr &&
+                    item->mType != MapItemType::EMPTY)
+                {
+                    c = f - x - 1;
+                    break;
+                }
+            }
+            mCache[x + y2] = c;
+        }
+    }
+}
diff --git a/src/resources/map/speciallayer.h b/src/resources/map/speciallayer.h
index 1c69ab4be..ba9470bff 100644
--- a/src/resources/map/speciallayer.h
+++ b/src/resources/map/speciallayer.h
@@ -57,16 +57,19 @@ class SpecialLayer final : public MemoryCounter
 
         void addRoad(const Path &road);
 
-        void clean() const;
+        void clean();
 
         int calcMemoryLocal() const override final;
 
         std::string getCounterName() const override final
         { return mName; }
 
+        void updateCache();
+
     private:
         const std::string mName;
         MapItem **mTiles;
+        int *mCache;
         int mWidth;
         int mHeight;
 };
-- 
cgit v1.2.3-70-g09d2