From e2921c64075d30009a34c4c003d06bc3c8e754ed Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Thu, 19 Jul 2012 03:34:22 -0300 Subject: [PATCH] Optimize map view zoomout performance --- src/otclient/game.cpp | 2 +- src/otclient/map.cpp | 16 +++- src/otclient/map.h | 1 + src/otclient/mapview.cpp | 168 ++++++++++++++------------------------- src/otclient/mapview.h | 5 +- src/otclient/position.h | 2 +- 6 files changed, 80 insertions(+), 114 deletions(-) diff --git a/src/otclient/game.cpp b/src/otclient/game.cpp index c8f7de9c..484de093 100644 --- a/src/otclient/game.cpp +++ b/src/otclient/game.cpp @@ -38,8 +38,8 @@ Game g_game; Game::Game() { resetGameStates(); - //setProtocolVersion(960); m_protocolVersion = 0; + setProtocolVersion(PROTOCOL); } void Game::resetGameStates() diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 52078cbf..3ce2c21e 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -553,10 +553,11 @@ void Map::clean() m_tiles.clear(); m_waypoints.clear(); - // This is a fix to a segfault on exit. m_towns.clear(); m_houses.clear(); m_creatures.clear(); + m_monsters.clear(); + m_tilesRect = Rect(65534, 65534, 0, 0); } void Map::cleanDynamicThings() @@ -693,15 +694,26 @@ TilePtr Map::createTile(const Position& pos) { TilePtr tile = TilePtr(new Tile(pos)); m_tiles[pos] = tile; + if(pos.x < m_tilesRect.left()) + m_tilesRect.setLeft(pos.x); + if(pos.y < m_tilesRect.top()) + m_tilesRect.setTop(pos.y); + if(pos.x > m_tilesRect.right()) + m_tilesRect.setRight(pos.x); + if(pos.y > m_tilesRect.bottom()) + m_tilesRect.setBottom(pos.y); return tile; } const TilePtr& Map::getTile(const Position& pos) { + static TilePtr nulltile; + if(!m_tilesRect.contains(Point(pos.x, pos.y))) + return nulltile; + auto it = m_tiles.find(pos); if(it != m_tiles.end()) return it->second; - static TilePtr nulltile; return nulltile; } diff --git a/src/otclient/map.h b/src/otclient/map.h index 7bb1231b..9e0b4622 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -185,6 +185,7 @@ private: Light m_light; Position m_centralPosition; + Rect m_tilesRect; std::string m_description, m_spawnFile, m_houseFile; diff --git a/src/otclient/mapview.cpp b/src/otclient/mapview.cpp index 43091974..61855839 100644 --- a/src/otclient/mapview.cpp +++ b/src/otclient/mapview.cpp @@ -41,6 +41,7 @@ MapView::MapView() m_lockedFirstVisibleFloor = -1; m_cachedFirstVisibleFloor = 7; m_cachedLastVisibleFloor = 7; + m_updateTilesPos = 0; m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS; m_framebuffer = g_framebuffers.createFrameBuffer(); @@ -57,8 +58,8 @@ MapView::~MapView() void MapView::draw(const Rect& rect) { // update visible tiles cache when needed - if(m_mustUpdateVisibleTilesCache) - updateVisibleTilesCache(); + if(m_mustUpdateVisibleTilesCache || m_updateTilesPos > 0) + updateVisibleTilesCache(m_mustUpdateVisibleTilesCache ? 0 : m_updateTilesPos); float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS; Position cameraPosition = getCameraPosition(); @@ -67,14 +68,8 @@ void MapView::draw(const Rect& rect) if(m_viewMode == NEAR_VIEW) drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems | Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawMissiles | Otc::DrawAnimations; - else if(m_viewMode == MID_VIEW) + else drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems; - else if(m_viewMode == FAR_VIEW) - drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls; - else if(m_tileSize >= 4) // HUGE_VIEW 1 - drawFlags = Otc::DrawGround | Otc::DrawGroundBorders; - else // HUGE_VIEW 2 - drawFlags = Otc::DrawGround; Size tileSize = Size(1,1) * m_tileSize; if(m_mustDrawVisibleTilesCache || (drawFlags & Otc::DrawAnimations)) { @@ -244,11 +239,6 @@ void MapView::draw(const Rect& rect) void MapView::updateVisibleTilesCache(int start) { if(start == 0) { - if(m_updateTilesCacheEvent) { - m_updateTilesCacheEvent->cancel(); - m_updateTilesCacheEvent = nullptr; - } - m_cachedFirstVisibleFloor = calcFirstVisibleFloor(); m_cachedLastVisibleFloor = calcLastVisibleFloor(); assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 && @@ -263,6 +253,7 @@ void MapView::updateVisibleTilesCache(int start) m_mustCleanFramebuffer = true; m_mustDrawVisibleTilesCache = true; m_mustUpdateVisibleTilesCache = false; + m_updateTilesPos = 0; } else m_mustCleanFramebuffer = false; @@ -271,12 +262,12 @@ void MapView::updateVisibleTilesCache(int start) if(!cameraPosition.isValid()) return; - int count = 0; bool stop = false; // clear current visible tiles cache m_cachedVisibleTiles.clear(); m_mustDrawVisibleTilesCache = true; + m_updateTilesPos = 0; // cache visible tiles in draw order // draw from last floor (the lower) to first floor (the higher) @@ -289,13 +280,13 @@ void MapView::updateVisibleTilesCache(int start) int advance = std::max(diagonal - m_drawDimension.height(), 0); for(int iy = diagonal - advance, ix = advance; iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) { // only start really looking tiles in the desired start - if(count < start) { - count++; + if(m_updateTilesPos < start) { + m_updateTilesPos++; continue; } - // avoid rendering too much tiles at once on far views - if(count - start + 1 > MAX_TILE_UPDATES && m_viewMode >= HUGE_VIEW) { + // avoid rendering too much tiles at once + if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS && m_viewMode >= HUGE_VIEW) { stop = true; break; } @@ -314,108 +305,63 @@ void MapView::updateVisibleTilesCache(int start) continue; m_cachedVisibleTiles.push_back(tile); } - count++; + m_updateTilesPos++; } } } else { - static std::vector points; - points.clear(); - //assert(m_drawDimension.width() % 2 == 0 && m_drawDimension.height() % 2 == 0); - Point quadTopLeft(m_drawDimension.width()/2 - 1, m_drawDimension.height()/2 - 1); - for(int step = 1; !(quadTopLeft.x < 0 && quadTopLeft.y < 0) && !stop; ++step) { - int quadWidth = std::min(2*step, m_drawDimension.width()); - int quadHeight = std::min(2*step, m_drawDimension.height()); - int fillWidth = (quadTopLeft.x >= 0) ? quadWidth-1 : quadWidth; - int fillHeight = (quadTopLeft.x >= 0) ? quadHeight-1 : quadHeight; - if(quadTopLeft.y >= 0) { - for(int qx=0;qx m_spiral; + if(start == 0) { + m_spiral.resize(m_drawDimension.area()); + int width = m_drawDimension.width(); + int height = m_drawDimension.height(); + int tpx = width/2 - 2; + int tpy = height/2 - 2; + int count = 0; + Rect area(0, 0, m_drawDimension); + m_spiral[count++] = Point(tpx+1,tpy+1); + for(int step = 1; tpx >= 0 || tpy >= 0; ++step, --tpx, --tpy) { + int qs = 2*step; + Rect lines[4] = { + Rect(tpx, tpy, qs, 1), + Rect(tpx + qs, tpy, 1, qs), + Rect(tpx + 1, tpy + qs, qs, 1), + Rect(tpx, tpy + 1, 1, qs), + }; - // avoid rendering too much tiles at once on far views - if(count - start + 1 > MAX_TILE_UPDATES) { - stop = true; - break; - } - points.push_back(Point(std::max(quadTopLeft.x, 0) + qx, quadTopLeft.y)); - count++; + for(int i=0;i<4;++i) { + int sx = std::max(lines[i].left(), area.left()); + int ex = std::min(lines[i].right(), area.right()); + int sy = std::max(lines[i].top(), area.top()); + int ey = std::min(lines[i].bottom(), area.bottom()); + for(int qx=sx;qx<=ex;++qx) + for(int qy=sy;qy<=ey;++qy) + m_spiral[count++] = Point(qx, qy); } } - if(quadTopLeft.x >= 0) { - for(int qy=0;qy MAX_TILE_UPDATES) { - stop = true; - break; - } - points.push_back(Point(quadTopLeft.x + quadWidth-1, std::max(quadTopLeft.y, 0) + qy)); - count++; - } - } - if(quadTopLeft.y >= 0) { - for(int qx=0;qx MAX_TILE_UPDATES) { - stop = true; - break; - } - points.push_back(Point(std::max(quadTopLeft.x, 0) + quadWidth-qx-1, quadTopLeft.y + quadHeight-1)); - count++; - } - } - if(quadTopLeft.x >= 0) { - for(int qy=0;qy MAX_TILE_UPDATES) { - stop = true; - break; - } - points.push_back(Point(quadTopLeft.x, std::max(quadTopLeft.y, 0) + quadHeight-qy-1)); - count++; - } - } - quadTopLeft -= Point(1,1); } - for(const Point& point : points) { - Position tilePos = cameraPosition.translated(point.x - m_virtualCenterOffset.x, point.y - m_virtualCenterOffset.y); - // adjust tilePos to the wanted floor + for(m_updateTilesPos = start; m_updateTilesPos < (int)m_spiral.size(); ++m_updateTilesPos) { + // avoid rendering too much tiles at once + if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS) { + stop = true; + break; + } + + const Point& p = m_spiral[m_updateTilesPos]; + Position tilePos = cameraPosition.translated(p.x - m_virtualCenterOffset.x, p.y - m_virtualCenterOffset.y); tilePos.coveredUp(cameraPosition.z - iz); if(const TilePtr& tile = g_map.getTile(tilePos)) { - // skip tiles that have nothing - if(tile->isEmpty()) - continue; - m_cachedVisibleTiles.push_back(tile); + if(!tile->isEmpty()) + m_cachedVisibleTiles.push_back(tile); } } } } - if(stop) { - // schedule next update continuation to avoid freezes - m_updateTilesCacheEvent = g_dispatcher.scheduleEvent(std::bind(&MapView::updateVisibleTilesCache, asMapView(), count), 1); + if(!stop) { + m_updateTilesPos = 0; + m_spiral.clear(); } if(start == 0 && m_drawTexts && m_viewMode <= NEAR_VIEW) @@ -462,6 +408,11 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized viewMode = FAR_VIEW; else viewMode = HUGE_VIEW; + + if(viewMode >= FAR_VIEW) + m_multifloor = false; + else + m_multifloor = true; } // draw actually more than what is needed to avoid massive recalculations on huge views @@ -473,6 +424,7 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized } */ + m_viewMode = viewMode; m_visibleDimension = visibleDimension; m_drawDimension = drawDimension; @@ -570,7 +522,7 @@ int MapView::calcFirstVisibleFloor() // this could happens if the player is not known yet if(cameraPosition.isValid()) { // avoid rendering multifloors in far views - if(m_viewMode >= FAR_VIEW || !m_multifloor) { + if(!m_multifloor) { z = cameraPosition.z; } else { // if nothing is limiting the view, the first visible floor is 0 @@ -620,7 +572,7 @@ int MapView::calcFirstVisibleFloor() int MapView::calcLastVisibleFloor() { - if(!m_multifloor || m_viewMode >= FAR_VIEW) + if(!m_multifloor) return calcFirstVisibleFloor(); int z = 7; diff --git a/src/otclient/mapview.h b/src/otclient/mapview.h index 51fff750..0e70b755 100644 --- a/src/otclient/mapview.h +++ b/src/otclient/mapview.h @@ -39,7 +39,7 @@ class MapView : public LuaObject NEAR_VIEW_AREA = 32*32, MID_VIEW_AREA = 64*64, FAR_VIEW_AREA = 128*128, - MAX_TILE_UPDATES = NEAR_VIEW_AREA*7 + MAX_TILE_DRAWS = NEAR_VIEW_AREA*7 }; public: @@ -127,6 +127,7 @@ private: int m_cachedFirstVisibleFloor; int m_cachedLastVisibleFloor; int m_tileSize; + int m_updateTilesPos; Size m_drawDimension; Size m_visibleDimension; Size m_optimizedSize; @@ -145,12 +146,12 @@ private: Boolean m_follow; std::vector m_cachedVisibleTiles; std::vector m_cachedFloorVisibleCreatures; - EventPtr m_updateTilesCacheEvent; CreaturePtr m_followingCreature; FrameBufferPtr m_framebuffer; PainterShaderProgramPtr m_shader; ViewMode m_viewMode; Otc::DrawFlags m_drawFlags; + std::vector m_spiral; }; #endif diff --git a/src/otclient/position.h b/src/otclient/position.h index d10aa6ab..580032da 100644 --- a/src/otclient/position.h +++ b/src/otclient/position.h @@ -214,7 +214,7 @@ public: struct PositionHasher : std::unary_function { std::size_t operator()(const Position& pos) const { - return (((((pos.x * 2048) + pos.y) * 16) + pos.z) % (2048*2048)) % 1000000; + return (((((pos.x * 8192) + pos.y) * 16) + pos.z) % (8192*8192)) % 100000000; } };