From 2835a66babf8ce13428291e85df590fdc0aa8046 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Fri, 6 Apr 2012 20:12:46 -0300 Subject: [PATCH] experimental minimap * a lot of rework in MapView * new APIs for UIMap --- modules/game/game.otmod | 1 + modules/game/widgets/uigamemap.lua | 2 + modules/game_minimap/minimap.lua | 64 +++++++ modules/game_minimap/minimap.otmod | 15 ++ modules/game_minimap/minimap.otui | 21 +++ modules/game_minimap/minimap.png | Bin 0 -> 910 bytes modules/game_shaders/map.frag | 76 ++++++++ src/framework/graphics/graphics.cpp | 4 +- src/framework/graphics/graphics.h | 2 - src/framework/math/color.h | 2 + src/otclient/core/mapview.cpp | 274 +++++++++++++++++----------- src/otclient/core/mapview.h | 66 +++++-- src/otclient/core/thing.h | 1 + src/otclient/core/tile.cpp | 13 ++ src/otclient/core/tile.h | 1 + src/otclient/luafunctions.cpp | 33 +++- src/otclient/ui/uimap.cpp | 125 ++++++++----- src/otclient/ui/uimap.h | 46 ++++- 18 files changed, 572 insertions(+), 174 deletions(-) create mode 100644 modules/game_minimap/minimap.lua create mode 100644 modules/game_minimap/minimap.otmod create mode 100644 modules/game_minimap/minimap.otui create mode 100644 modules/game_minimap/minimap.png diff --git a/modules/game/game.otmod b/modules/game/game.otmod index 9810062f..498b117b 100644 --- a/modules/game/game.otmod +++ b/modules/game/game.otmod @@ -20,6 +20,7 @@ Module - game_containers - game_viplist - game_battle + - game_minimap - game_hotkeys @onLoad: | diff --git a/modules/game/widgets/uigamemap.lua b/modules/game/widgets/uigamemap.lua index 3420c40b..2f0a181a 100644 --- a/modules/game/widgets/uigamemap.lua +++ b/modules/game/widgets/uigamemap.lua @@ -2,6 +2,8 @@ UIGameMap = extends(UIMap) function UIGameMap.create() local gameMap = UIGameMap.internalCreate() + gameMap:setKeepAspectRatio(true) + gameMap:setVisibleDimension({width = 15, height = 11}) return gameMap end diff --git a/modules/game_minimap/minimap.lua b/modules/game_minimap/minimap.lua new file mode 100644 index 00000000..57d9af74 --- /dev/null +++ b/modules/game_minimap/minimap.lua @@ -0,0 +1,64 @@ +Minimap = {} + +-- private variables +local minimapWidget +local minimapButton + +-- private functions +function onMinimapMouseRelease(self, mousePosition, mouseButton) + local tile = self:getTile(mousePosition) + if tile and mouseButton == MouseLeftButton and self:isPressed() then + local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), tile:getPosition(), 255) + if #dirs == 0 then + TextMessage.displayStatus('There is no way.') + return true + end + g_game.autoWalk(dirs) + return true + end + return false +end + + +function onMinimapMouseWheel(self, mousePos, direction) + if direction == MouseWheelUp then + self:zoomIn() + else + self:zoomOut() + end +end + +-- public functions +function Minimap.init() + connect(g_game, { onLogin = Minimap.reset }) + Keyboard.bindKeyDown('Ctrl+M', Minimap.toggle) + + minimapButton = TopMenu.addGameToggleButton('minimapButton', 'Minimap (Ctrl+M)', 'minimap.png', Minimap.toggle) + minimapButton:setOn(true) + + minimapWidget = loadUI('minimap.otui', GameInterface.getMapPanel()) + minimapWidget.onMouseRelease = onMinimapMouseRelease + minimapWidget.onMouseWheel = onMinimapMouseWheel +end + +function Minimap.terminate() + Keyboard.unbindKeyDown('Ctrl+M') + disconnect(g_game, { onLogin = Minimap.reset }) + + minimapWidget:destroy() + minimapWidget = nil + minimapButton:destroy() + minimapButton = nil +end + +function Minimap.toggle() + local visible = not minimapWidget:isExplicitlyVisible() + minimapWidget:setVisible(visible) + minimapButton:setOn(visible) +end + +function Minimap.reset() + minimapWidget:followCreature(g_game.getLocalPlayer()) + for i=1,10 do minimapWidget:zoomOut() end +end + diff --git a/modules/game_minimap/minimap.otmod b/modules/game_minimap/minimap.otmod new file mode 100644 index 00000000..82301708 --- /dev/null +++ b/modules/game_minimap/minimap.otmod @@ -0,0 +1,15 @@ +Module + name: game_minimap + description: Manage minimap + author: OTClient team + website: https://github.com/edubart/otclient + + dependecies: + - game + + @onLoad: | + dofile 'minimap' + Minimap.init() + + @onUnload: + Minimap.terminate() diff --git a/modules/game_minimap/minimap.otui b/modules/game_minimap/minimap.otui new file mode 100644 index 00000000..1a90d79e --- /dev/null +++ b/modules/game_minimap/minimap.otui @@ -0,0 +1,21 @@ +UIMap + id: minimap + anchors.top: parent.top + anchors.right: parent.right + size: 256 192 + margin-top: 2 + margin-right: 2 + border-width: 1 + border-color: #888888 + padding: 1 + //draw-minimap-colors: true + multifloor: false + draw-texts: false + + CheckBox + anchors.top: parent.top + anchors.right: parent.right + margin-top: 2 + margin-right: 2 + size: 16 16 + @onCheckChange: self:getParent():setDrawMinimapColors(self:isChecked()) \ No newline at end of file diff --git a/modules/game_minimap/minimap.png b/modules/game_minimap/minimap.png new file mode 100644 index 0000000000000000000000000000000000000000..8ec6efe8db788df7a44723bf685b770ed9eccd28 GIT binary patch literal 910 zcmV;919AL`P)kybVpoxM9$LykQ6L^m&OS!QF|JZU4w_2fM9#q#ZMW4{t`#3H@oXV~&mAD^ObHufGFb=8C|6^jqZ(B#XY2TR28u&x=w)WcWDKx3*DU zbefcwM@A2jwLGdOg0pf2g>?Kx-(bt$;_`C*lE}@q=^5_kG4&muso%q?p>DQReMWJ9 z6A3j$N%#sUFLYuh7Eb(|CDrRXdnWIy+C*L;C{%TETm{_f6}5{yWhtB3$wK zPnTcj%FyfF{AgQ^Xrw8xk*2iaUpkW0<0La_Qo1cdRZ*>kfGiPRd{E>|&IZPsxp4Ua z>hPHk&u=9HZxxm8JG4K);i<3f{1U7{0j8vgjuQ%rnzTOB&aZ#A5|1@vUOU~f^uwpe zgirF0Ve%ltHdnrP?0u!EY_}vye!~|;&M7Y&c5?3I?2)}+h&yAR^Z%xC)v6X&>Q!jf knP?{#SHfOB&i@E70Q(eglU)(D^Z)<=07*qoM6N<$g0&O7BLDyZ literal 0 HcmV?d00001 diff --git a/modules/game_shaders/map.frag b/modules/game_shaders/map.frag index c88317ba..3dd5d822 100644 --- a/modules/game_shaders/map.frag +++ b/modules/game_shaders/map.frag @@ -3,8 +3,84 @@ uniform vec4 color; // painter color uniform float time; // time in seconds since shader linkage uniform sampler2D texture; // map texture varying vec2 textureCoords; // map texture coords +//uniform vec4 awareArea; void main() { gl_FragColor = texture2D(texture, textureCoords); } + +/* +vec4 grayScale(vec4 color, float factor) +{ + float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); + return vec4(gray*factor + (1-factor)*color.r, + gray*factor + (1-factor)*color.g, + gray*factor + (1-factor)*color.b, 1); +} + +// grayscale fog +void main() +{ + vec4 color = texture2D(texture, textureCoords); + float dist = 0; + // left + if(textureCoords.x < awareArea.x && textureCoords.y < awareArea.y) + dist = distance(textureCoords, awareArea.xy); + else if(textureCoords.x < awareArea.x && textureCoords.y < awareArea.w) + dist = distance(textureCoords, vec2(awareArea.x, textureCoords.y)); + else if(textureCoords.x < awareArea.x) + dist = distance(textureCoords, awareArea.xw); + // right + else if(textureCoords.x > awareArea.z && textureCoords.y < awareArea.y) + dist = distance(textureCoords, awareArea.zy); + else if(textureCoords.x > awareArea.z && textureCoords.y < awareArea.w) + dist = distance(textureCoords, vec2(awareArea.z, textureCoords.y)); + else if(textureCoords.x > awareArea.z) + dist = distance(textureCoords, awareArea.zw); + // top + else if(textureCoords.y < awareArea.y) + dist = distance(textureCoords, vec2(textureCoords.x, awareArea.y)); + // bottom + else if(textureCoords.y > awareArea.w) + dist = distance(textureCoords, vec2(textureCoords.x, awareArea.w)); + if(dist > 0) { + float range = 0.01; + float factor = min(dist/range, 1.0); + color = grayScale(color, factor); + //color.rgb *= 1 - (factor * 0.5); + } + gl_FragColor = color; +} +*/ + +/* +sepia +void main() +{ + vec4 color = texture2D(texture, textureCoords); + if(textureCoords.x < awareArea.x || textureCoords.y < awareArea.y || textureCoords.x > awareArea.z || textureCoords.y > awareArea.w) { + gl_FragColor.r = dot(color, vec4(.393, .769, .189, .0)); + gl_FragColor.g = dot(color, vec4(.349, .686, .168, .0)); + gl_FragColor.b = dot(color, vec4(.272, .534, .131, .0)); + gl_FragColor.a = 1; + } else + gl_FragColor = color; +} +*/ + +/* +void main() +{ + vec4 color = texture2D(texture, textureCoords); + vec2 awareRange = (awareArea.zw - awareArea.xy)/2.0; + float dist = distance(textureCoords, awareArea.xy + awareRange); + float start = min(awareRange.x, awareRange.y); + float range = awareRange*0.1; + float endFactor = 0.3; + if(dist >= start) { + color.rgb *= 1 - (min((dist - start)/range, 1.0) * (2.0 - endFactor)); + } + gl_FragColor = color; +} +*/ \ No newline at end of file diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index 6154d2e1..932c7e48 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -76,6 +76,8 @@ void Graphics::init() #endif + glHint(GL_LINE_SMOOTH_HINT,GL_NICEST); + glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); glEnable(GL_BLEND); glClear(GL_COLOR_BUFFER_BIT); @@ -99,8 +101,6 @@ bool Graphics::parseOption(const std::string& option) m_generateMipmaps = false; else if(option == "-no-smoothing") m_useBilinearFiltering = false; - else if(option == "-realtime-mipmapping") - m_generateRealtimeMipmaps = true; else if(option == "-no-hardware-buffering") m_useHardwareBuffers = false; else diff --git a/src/framework/graphics/graphics.h b/src/framework/graphics/graphics.h index 3699eeb9..85e25934 100644 --- a/src/framework/graphics/graphics.h +++ b/src/framework/graphics/graphics.h @@ -38,7 +38,6 @@ public: bool canUseHardwareBuffers() { return m_useHardwareBuffers; } bool canGenerateMipmaps() { return m_generateMipmaps; } bool canGenerateHardwareMipmaps() { return m_generateHardwareMipmaps; } - bool canGenerateRealtimeMipmaps() { return m_generateRealtimeMipmaps; } void resize(const Size& size); void beginRender(); @@ -59,7 +58,6 @@ private: Boolean m_useBilinearFiltering; Boolean m_generateMipmaps; Boolean m_generateHardwareMipmaps; - Boolean m_generateRealtimeMipmaps; }; extern Graphics g_graphics; diff --git a/src/framework/math/color.h b/src/framework/math/color.h index b319df89..e23cb7b9 100644 --- a/src/framework/math/color.h +++ b/src/framework/math/color.h @@ -33,6 +33,8 @@ public: Color() : m_r(1.0f), m_g(1.0f), m_b(1.0f), m_a(1.0f) { } Color(uint32 rgba) { setRGBA(rgba); } Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : m_r(r/255.0f), m_g(g/255.0f), m_b(b/255.0f), m_a(a/255.0f) { } + Color(int r, int g, int b, int a = 0xFF) : m_r(r/255.0f), m_g(g/255.0f), m_b(b/255.0f), m_a(a/255.0f) { } + Color(float r, float g, float b, float a = 1.0f) : m_r(r), m_g(g), m_b(b), m_a(a) { } uint8 a() const { return m_a*255.0f; } uint8 b() const { return m_b*255.0f; } diff --git a/src/otclient/core/mapview.cpp b/src/otclient/core/mapview.cpp index 9a1a318c..4fe8ffbe 100644 --- a/src/otclient/core/mapview.cpp +++ b/src/otclient/core/mapview.cpp @@ -34,23 +34,24 @@ #include "missile.h" #include +//int AWARE_AREA_UNIFORM = 10; + MapView::MapView() { - m_viewRange = NEAR_VIEW; + m_viewMode = NEAR_VIEW; m_lockedFirstVisibleFloor = -1; - m_cachedFirstVisibleFloor = 0; + m_cachedFirstVisibleFloor = 7; m_cachedLastVisibleFloor = 7; + m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS; - Size frameBufferSize(std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_WIDTH), - std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_HEIGHT)); - - m_framebuffer = FrameBufferPtr(new FrameBuffer(frameBufferSize)); + m_framebuffer = FrameBufferPtr(new FrameBuffer()); setVisibleDimension(Size(15, 11)); m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram); m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag"); m_shaderProgram->link(); + //m_shaderProgram->bindUniformLocation(AWARE_AREA_UNIFORM, "awareArea"); } void MapView::draw(const Rect& rect) @@ -63,18 +64,19 @@ void MapView::draw(const Rect& rect) Position cameraPosition = getCameraPosition(); int drawFlags = 0; - if(m_viewRange == NEAR_VIEW) + 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_viewRange == MID_VIEW) + else if(m_viewMode == MID_VIEW) drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems; - else if(m_viewRange == FAR_VIEW) + 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)) { g_painter.saveAndResetState(); m_framebuffer->bind(); @@ -86,6 +88,8 @@ void MapView::draw(const Rect& rect) g_painter.setColor(Color::black); g_painter.drawFilledRect(clearRect); g_painter.setColor(Color::white); + + // m_framebuffer->clear(Color::black); } auto it = m_cachedVisibleTiles.begin(); @@ -98,29 +102,26 @@ void MapView::draw(const Rect& rect) else ++it; - tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor, drawFlags); + if(!m_drawMinimapColors) + tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor, drawFlags); + else { + g_painter.setColor(tile->getMinimapColor()); + g_painter.drawFilledRect(Rect(transformPositionTo2D(tile->getPosition()), tileSize)); + } } - if(drawFlags & Otc::DrawMissiles) { + if(drawFlags & Otc::DrawMissiles && !m_drawMinimapColors) { for(const MissilePtr& missile : g_map.getFloorMissiles(z)) { missile->draw(transformPositionTo2D(missile->getPosition()), scaleFactor, drawFlags & Otc::DrawAnimations); } } } - /* - // debug source area - g_painter.setColor(Color(255,255,255,100)); - Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * m_tileSize; - g_painter.drawFilledRect(Rect(drawOffset, m_visibleDimension * m_tileSize)); - */ - m_framebuffer->release(); g_painter.restoreSavedState(); // generating mipmaps each frame can be slow in older cards - if(g_graphics.canGenerateRealtimeMipmaps()) - m_framebuffer->getTexture()->generateHardwareMipmaps(); + //m_framebuffer->getTexture()->generateHardwareMipmaps(); m_mustDrawVisibleTilesCache = false; } @@ -130,20 +131,57 @@ void MapView::draw(const Rect& rect) Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * m_tileSize; if(m_followingCreature) drawOffset += m_followingCreature->getWalkOffset() * scaleFactor; - Rect srcRect = Rect(drawOffset, m_visibleDimension * m_tileSize); + + Size srcSize = rect.size(); + Size srcVisible = m_visibleDimension * m_tileSize; + srcSize.scale(srcVisible, Fw::KeepAspectRatio); + drawOffset.x += (srcVisible.width() - srcSize.width()) / 2; + drawOffset.y += (srcVisible.height() - srcSize.height()) / 2; + Rect srcRect = Rect(drawOffset, srcSize); + + /* + // pass aware area to the shader program + Rect awareRect; + if(m_followingCreature) { + Point awareOffset = transformPositionTo2D(m_followingCreature->getPosition().translated(-Otc::AWARE_X_LEFT_TILES + 1, -Otc::AWARE_Y_TOP_TILES + 1)); + awareOffset += m_followingCreature->getWalkOffset() * scaleFactor; + + awareRect.setTopLeft(awareOffset); + awareRect.resize(Otc::VISIBLE_X_TILES * m_tileSize, Otc::VISIBLE_Y_TILES * m_tileSize); + } + + m_shaderProgram->bind(); + m_shaderProgram->setUniformValue(AWARE_AREA_UNIFORM, + awareRect.left()/(float)m_framebuffer->getSize().width(), + awareRect.top()/(float)m_framebuffer->getSize().height(), + awareRect.right()/(float)m_framebuffer->getSize().width(), + awareRect.bottom()/(float)m_framebuffer->getSize().height()); + */ + +#if 0 + // debug source area + g_painter.saveAndResetState(); + m_framebuffer->bind(); + g_painter.setColor(Color::green); + g_painter.drawBoundingRect(srcRect, 2); + m_framebuffer->release(); + g_painter.restoreSavedState(); + m_framebuffer->draw(rect); +#else m_framebuffer->draw(rect, srcRect); +#endif + g_painter.releaseCustomProgram(); // this could happen if the player position is not known yet if(!cameraPosition.isValid()) return; - float horizontalStretchFactor = rect.width() / (float)(m_visibleDimension.width() * m_tileSize); - float verticalStretchFactor = rect.height() / (float)(m_visibleDimension.height() * m_tileSize); - //Size tileStretchedSize = Size(m_tileSize * horizontalStretchFactor, m_tileSize * verticalStretchFactor); + float horizontalStretchFactor = rect.width() / (float)srcRect.width(); + float verticalStretchFactor = rect.height() / (float)srcRect.height(); // avoid drawing texts on map in far zoom outs - if(m_viewRange == NEAR_VIEW) { + if(m_viewMode == NEAR_VIEW && m_drawTexts) { for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) { Position pos = creature->getPosition(); @@ -187,7 +225,7 @@ void MapView::draw(const Rect& rect) p += rect.topLeft(); animatedText->draw(p, rect); } - } else { + } else if(m_viewMode > NEAR_VIEW) { // draw a cross in the center instead of our creature Rect vRect(0, 0, 2, 10); Rect hRect(0, 0, 10, 2); @@ -239,16 +277,13 @@ void MapView::updateVisibleTilesCache(int start) // cache visible tiles in draw order // draw from last floor (the lower) to first floor (the higher) for(int iz = m_cachedLastVisibleFloor; iz >= m_cachedFirstVisibleFloor && !stop; --iz) { - if(m_viewRange <= FAR_VIEW) { + if(m_viewMode <= FAR_VIEW) { const int numDiagonals = m_drawDimension.width() + m_drawDimension.height() - 1; // loop through / diagonals beginning at top left and going to top right for(int diagonal = 0; diagonal < numDiagonals && !stop; ++diagonal) { // loop current diagonal tiles - for(int iy = std::min(diagonal, m_drawDimension.width() - 1), ix = std::max(diagonal - m_drawDimension.width() + 1, 0); iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) { - // skip bottom tiles that are outside the draw dimension - if(iy >= m_drawDimension.height()) - continue; - + 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++; @@ -256,7 +291,7 @@ void MapView::updateVisibleTilesCache(int start) } // avoid rendering too much tiles at once on far views - if(count - start + 1 > MAX_TILE_UPDATES && m_viewRange >= HUGE_VIEW) { + if(count - start + 1 > MAX_TILE_UPDATES && m_viewMode >= HUGE_VIEW) { stop = true; break; } @@ -378,13 +413,71 @@ void MapView::updateVisibleTilesCache(int start) // schedule next update continuation to avoid freezes m_updateTilesCacheEvent = g_eventDispatcher.scheduleEvent(std::bind(&MapView::updateVisibleTilesCache, asMapView(), count), 1); } - if(start == 0) + + if(start == 0 && m_drawTexts && m_viewMode <= NEAR_VIEW) m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false); } +void MapView::updateGeometry(const Size& visibleDimension, const Size& optimizedSize) +{ + int possiblesTileSizes[] = {1,2,4,8,16,32}; + int tileSize = 0; + Size bufferSize; + for(int candidateTileSize : possiblesTileSizes) { + bufferSize = (visibleDimension + Size(3,3)) * candidateTileSize; + if(bufferSize.width() > g_graphics.getMaxTextureSize() || bufferSize.height() > g_graphics.getMaxTextureSize()) + break; + + tileSize = candidateTileSize; + if(optimizedSize.width() < bufferSize.width() - 3*candidateTileSize && optimizedSize.height() < bufferSize.height() - 3*candidateTileSize) + break; + } + + if(tileSize == 0) { + logTraceError("reached max zoom out"); + return; + } + + Size drawDimension = visibleDimension + Size(3,3); + Point virtualCenterOffset = (drawDimension/2 - Size(1,1)).toPoint(); + Point visibleCenterOffset = virtualCenterOffset; + + ViewMode viewMode = m_viewMode; + if(m_autoViewMode) { + if(tileSize >= 32 && visibleDimension.area() <= NEAR_VIEW_AREA) + viewMode = NEAR_VIEW; + else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA) + viewMode = MID_VIEW; + else if(tileSize >= 8 && visibleDimension.area() <= FAR_VIEW_AREA) + viewMode = FAR_VIEW; + else + viewMode = HUGE_VIEW; + } + + // draw actually more than what is needed to avoid massive recalculations on huge views + /* + if(viewMode >= HUGE_VIEW) { + Size oldDimension = drawDimension; + drawDimension = (m_framebuffer->getSize() / tileSize); + virtualCenterOffset += (drawDimension - oldDimension).toPoint() / 2; + } + */ + + m_viewMode = viewMode; + m_visibleDimension = visibleDimension; + m_drawDimension = drawDimension; + m_tileSize = tileSize; + m_virtualCenterOffset = virtualCenterOffset; + m_visibleCenterOffset = visibleCenterOffset; + m_optimizedSize = optimizedSize; + m_framebuffer->resize(bufferSize); + + requestVisibleTilesCacheUpdate(); +} + void MapView::onTileUpdate(const Position& pos) { - //if(m_viewRange <= FAR_VIEW) + //if(m_viewMode <= FAR_VIEW) requestVisibleTilesCacheUpdate(); } @@ -400,21 +493,11 @@ void MapView::unlockFirstVisibleFloor() requestVisibleTilesCacheUpdate(); } -void MapView::followCreature(const CreaturePtr& creature) -{ - m_followingCreature = creature; - requestVisibleTilesCacheUpdate(); -} - -void MapView::setCameraPosition(const Position& pos) -{ - m_customCameraPosition = pos; - m_followingCreature = nullptr; - requestVisibleTilesCacheUpdate(); -} - void MapView::setVisibleDimension(const Size& visibleDimension) { + if(visibleDimension == m_visibleDimension) + return; + if(visibleDimension.width() % 2 != 1 || visibleDimension.height() % 2 != 1) { logTraceError("visible dimension must be odd"); return; @@ -425,53 +508,38 @@ void MapView::setVisibleDimension(const Size& visibleDimension) return; } - int possiblesTileSizes[] = {32,16,8,4,2,1}; - int tileSize = 0; - Size drawDimension = visibleDimension + Size(3,3); - Size framebufferSize = m_framebuffer->getSize(); - for(int candidateTileSize : possiblesTileSizes) { - Size candidateDrawSize = drawDimension * candidateTileSize; - - // found a valid size - if(candidateDrawSize.width() <= framebufferSize.width() && candidateDrawSize.height() <= framebufferSize.height()) { - tileSize = candidateTileSize; - break; - } - } + updateGeometry(visibleDimension, m_optimizedSize); +} - if(tileSize == 0) { - logTraceError("reached max zoom out"); - return; - } +void MapView::setViewMode(MapView::ViewMode viewMode) +{ + m_viewMode = viewMode; + requestVisibleTilesCacheUpdate(); +} - Point virtualCenterOffset = (drawDimension/2 - Size(1,1)).toPoint(); - Point visibleCenterOffset = virtualCenterOffset; +void MapView::setAutoViewMode(bool enable) +{ + m_autoViewMode = enable; + if(enable) + updateGeometry(m_visibleDimension, m_optimizedSize); +} - ViewRange viewRange; - if(tileSize >= 32 && visibleDimension.area() <= NEAR_VIEW_AREA) - viewRange = NEAR_VIEW; - else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA) - viewRange = MID_VIEW; - else if(tileSize >= 8 && visibleDimension.area() <= FAR_VIEW_AREA) - viewRange = FAR_VIEW; - else - viewRange = HUGE_VIEW; - - bool mustUpdate = (m_drawDimension != drawDimension || - m_viewRange != viewRange || - m_virtualCenterOffset != virtualCenterOffset || - m_visibleCenterOffset != visibleCenterOffset || - m_tileSize != tileSize); +void MapView::optimizeForSize(const Size& visibleSize) +{ + updateGeometry(m_visibleDimension, visibleSize); +} - m_visibleDimension = visibleDimension; - m_drawDimension = drawDimension; - m_tileSize = tileSize; - m_viewRange = viewRange; - m_virtualCenterOffset = virtualCenterOffset; - m_visibleCenterOffset = visibleCenterOffset; +void MapView::followCreature(const CreaturePtr& creature) +{ + m_followingCreature = creature; + requestVisibleTilesCacheUpdate(); +} - if(mustUpdate) - requestVisibleTilesCacheUpdate(); +void MapView::setCameraPosition(const Position& pos) +{ + m_customCameraPosition = pos; + m_followingCreature = nullptr; + requestVisibleTilesCacheUpdate(); } int MapView::calcFirstVisibleFloor() @@ -486,7 +554,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_viewRange >= FAR_VIEW) { + if(m_viewMode >= FAR_VIEW || !m_multifloor) { z = cameraPosition.z; } else { // if nothing is limiting the view, the first visible floor is 0 @@ -536,23 +604,24 @@ int MapView::calcFirstVisibleFloor() int MapView::calcLastVisibleFloor() { + if(!m_multifloor || m_viewMode >= FAR_VIEW) + return calcFirstVisibleFloor(); + int z = 7; Position cameraPosition = getCameraPosition(); // this could happens if the player is not known yet if(cameraPosition.isValid()) { - // avoid rendering multifloors in far views - if(m_viewRange >= FAR_VIEW) { - z = cameraPosition.z; - } else { - // view only underground floors when below sea level - if(cameraPosition.z > Otc::SEA_FLOOR) - z = cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; - else - z = Otc::SEA_FLOOR; - } + // view only underground floors when below sea level + if(cameraPosition.z > Otc::SEA_FLOOR) + z = cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; + else + z = Otc::SEA_FLOOR; } + if(m_lockedFirstVisibleFloor != -1) + z = std::max(m_lockedFirstVisibleFloor, z); + // just ensure the that the floor is in the valid range z = std::min(std::max(z, 0), (int)Otc::MAX_Z); return z; @@ -568,7 +637,7 @@ Position MapView::getCameraPosition() TilePtr MapView::getTile(const Point& mousePos, const Rect& mapRect) { Point relativeMousePos = mousePos - mapRect.topLeft(); - Size visibleSize = getVisibleSize(); + Size visibleSize = m_visibleDimension * m_tileSize; Position cameraPosition = getCameraPosition(); // if we have no camera, its impossible to get the tile @@ -608,6 +677,7 @@ TilePtr MapView::getTile(const Point& mousePos, const Rect& mapRect) return tile; } + Point MapView::transformPositionTo2D(const Position& position) { Position cameraPosition = getCameraPosition(); diff --git a/src/otclient/core/mapview.h b/src/otclient/core/mapview.h index 6c5445fc..6da8265b 100644 --- a/src/otclient/core/mapview.h +++ b/src/otclient/core/mapview.h @@ -34,8 +34,6 @@ class MapView : public LuaObject // 3840x2160 => 1080p optimized // 2560x1440 => 720p optimized // 1728x972 => 480p optimized - DEFAULT_FRAMBUFFER_WIDTH = 2560, - DEFAULT_FRAMBUFFER_HEIGHT = 1440, NEAR_VIEW_AREA = 32*32, MID_VIEW_AREA = 64*64, @@ -43,18 +41,19 @@ class MapView : public LuaObject MAX_TILE_UPDATES = NEAR_VIEW_AREA*7 }; - enum ViewRange { +public: + enum ViewMode { NEAR_VIEW, MID_VIEW, FAR_VIEW, HUGE_VIEW }; -public: MapView(); void draw(const Rect& rect); private: + void updateGeometry(const Size& visibleDimension, const Size& optimizedSize); void updateVisibleTilesCache(int start = 0); void requestVisibleTilesCacheUpdate() { m_mustUpdateVisibleTilesCache = true; } @@ -64,55 +63,82 @@ protected: friend class Map; public: + // floor visibility related void lockFirstVisibleFloor(int firstVisibleFloor); void unlockFirstVisibleFloor(); - void followCreature(const CreaturePtr& creature); + int getLockedFirstVisibleFloor() { return m_lockedFirstVisibleFloor; } - void setCameraPosition(const Position& pos); + void setMultifloor(bool enable) { m_multifloor = enable; requestVisibleTilesCacheUpdate(); } + bool isMultifloor() { return m_multifloor; } + + // map dimension related void setVisibleDimension(const Size& visibleDimension); - void setAnimated(bool animated) { m_animated = animated; } + Size getVisibleDimension() { return m_visibleDimension; } - //void zoomIn(float factor); - //void zoomOut(float factor); + // view mode related + void setViewMode(ViewMode viewMode); + ViewMode getViewMode() { return m_viewMode; } + void optimizeForSize(const Size& visibleSize); - bool isFollowingCreature() { return !!m_followingCreature; } + void setAutoViewMode(bool enable); + bool isAutoViewModeEnabled() { return m_autoViewMode; } - int calcFirstVisibleFloor(); - int calcLastVisibleFloor(); - Position getCameraPosition(); - TilePtr getTile(const Point& mousePos, const Rect& mapRect); - Size getVisibleDimension() { return m_visibleDimension; } - Size getVisibleSize() { return m_visibleDimension * m_tileSize; } + // camera related + void followCreature(const CreaturePtr& creature); CreaturePtr getFollowingCreature() { return m_followingCreature; } - bool getViewRange() { return m_viewRange; } - bool isAnimated() { return m_animated; } + void setCameraPosition(const Position& pos); + Position getCameraPosition(); - Point transformPositionTo2D(const Position& position); + // drawing related + void setDrawFlags(Otc::DrawFlags drawFlags) { m_drawFlags = drawFlags; requestVisibleTilesCacheUpdate(); } + Otc::DrawFlags getDrawFlags() { return m_drawFlags; } + + void setDrawTexts(bool enable) { m_drawTexts = enable; } + bool isDrawingTexts() { return m_drawTexts; } + + void setDrawMinimapColors(bool enable) { m_drawMinimapColors = enable; requestVisibleTilesCacheUpdate(); } + bool isDrawingMinimapColors() { return m_drawMinimapColors; } + + void setAnimated(bool animated) { m_animated = animated; requestVisibleTilesCacheUpdate(); } + bool isAnimating() { return m_animated; } + + // get tile + TilePtr getTile(const Point& mousePos, const Rect& mapRect); MapViewPtr asMapView() { return std::static_pointer_cast(shared_from_this()); } private: + int calcFirstVisibleFloor(); + int calcLastVisibleFloor(); + Point transformPositionTo2D(const Position& position); + int m_lockedFirstVisibleFloor; int m_cachedFirstVisibleFloor; int m_cachedLastVisibleFloor; int m_tileSize; Size m_drawDimension; Size m_visibleDimension; + Size m_optimizedSize; Point m_virtualCenterOffset; Point m_visibleCenterOffset; Position m_customCameraPosition; Boolean m_mustUpdateVisibleTilesCache; Boolean m_mustDrawVisibleTilesCache; Boolean m_mustCleanFramebuffer; + Boolean m_multifloor; Boolean m_animated; + Boolean m_autoViewMode; + Boolean m_drawTexts; + Boolean m_drawMinimapColors; std::vector m_cachedVisibleTiles; std::vector m_cachedFloorVisibleCreatures; EventPtr m_updateTilesCacheEvent; CreaturePtr m_followingCreature; FrameBufferPtr m_framebuffer; PainterShaderProgramPtr m_shaderProgram; - ViewRange m_viewRange; + ViewMode m_viewMode; + Otc::DrawFlags m_drawFlags; }; #endif diff --git a/src/otclient/core/thing.h b/src/otclient/core/thing.h index 2f8e8608..4463682d 100644 --- a/src/otclient/core/thing.h +++ b/src/otclient/core/thing.h @@ -104,6 +104,7 @@ public: int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; } int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; } int getElevation() { return m_type->parameters[ThingType::Elevation]; } + int getMinimapColor() { return m_type->parameters[ThingType::MiniMapColor]; } int getSpriteId(int w = 0, int h = 0, int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index 347f5aa7..134be456 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -265,6 +265,19 @@ int Tile::getGroundSpeed() return groundSpeed; } +Color Tile::getMinimapColor() +{ + Color color = Color::black; + for(const ThingPtr& thing : m_things) { + if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()) + break; + int c = thing->getMinimapColor(); + if(c != 0) + color = Color::from8bit(c); + } + return color; +} + ThingPtr Tile::getTopLookThing() { if(isEmpty()) diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 3771ec44..2720fbc6 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -57,6 +57,7 @@ public: const std::vector& getThings() { return m_things; } ItemPtr getGround(); int getGroundSpeed(); + Color getMinimapColor(); int getThingCount() { return m_things.size() + m_effects.size(); } bool isPathable(); bool isWalkable(); diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 416fdb1c..ed6c63c9 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -333,10 +333,37 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("isFixedCreatureSize", &UICreature::isFixedCreatureSize); g_lua.registerClass(); - g_lua.bindClassStaticFunction("create", []{ return UIMapPtr(new UIMap); } ); + g_lua.bindClassStaticFunction("create", []{ return UIMapPtr(new UIMap); }); + g_lua.bindClassMemberFunction("drawSelf", &UIMap::drawSelf); + g_lua.bindClassMemberFunction("setZoom", &UIMap::setZoom); + g_lua.bindClassMemberFunction("zoomIn", &UIMap::zoomIn); + g_lua.bindClassMemberFunction("zoomOut", &UIMap::zoomOut); g_lua.bindClassMemberFunction("followCreature", &UIMap::followCreature); g_lua.bindClassMemberFunction("setCameraPosition", &UIMap::setCameraPosition); + g_lua.bindClassMemberFunction("setMaxZoomIn", &UIMap::setMaxZoomIn); + g_lua.bindClassMemberFunction("setMaxZoomOut", &UIMap::setMaxZoomOut); + g_lua.bindClassMemberFunction("setMultifloor", &UIMap::setMultifloor); + g_lua.bindClassMemberFunction("setVisibleDimension", &UIMap::setVisibleDimension); + g_lua.bindClassMemberFunction("setViewMode", &UIMap::setViewMode); + g_lua.bindClassMemberFunction("setAutoViewMode", &UIMap::setAutoViewMode); + g_lua.bindClassMemberFunction("setDrawFlags", &UIMap::setDrawFlags); + g_lua.bindClassMemberFunction("setDrawTexts", &UIMap::setDrawTexts); + g_lua.bindClassMemberFunction("setDrawMinimapColors", &UIMap::setDrawMinimapColors); + g_lua.bindClassMemberFunction("setAnimated", &UIMap::setAnimated); + g_lua.bindClassMemberFunction("setKeepAspectRatio", &UIMap::setKeepAspectRatio); + g_lua.bindClassMemberFunction("isMultifloor", &UIMap::isMultifloor); + g_lua.bindClassMemberFunction("isAutoViewModeEnabled", &UIMap::isAutoViewModeEnabled); + g_lua.bindClassMemberFunction("isDrawingTexts", &UIMap::isDrawingTexts); + g_lua.bindClassMemberFunction("isDrawingMinimapColors", &UIMap::isDrawingMinimapColors); + g_lua.bindClassMemberFunction("isAnimating", &UIMap::isAnimating); + g_lua.bindClassMemberFunction("isKeepAspectRatioEnabled", &UIMap::isKeepAspectRatioEnabled); + g_lua.bindClassMemberFunction("getVisibleDimension", &UIMap::getVisibleDimension); + g_lua.bindClassMemberFunction("getViewMode", &UIMap::getViewMode); + g_lua.bindClassMemberFunction("getFollowingCreature", &UIMap::getFollowingCreature); + g_lua.bindClassMemberFunction("getDrawFlags", &UIMap::getDrawFlags); + g_lua.bindClassMemberFunction("getCameraPosition", &UIMap::getCameraPosition); g_lua.bindClassMemberFunction("getTile", &UIMap::getTile); - g_lua.bindClassMemberFunction("zoomIn", &UIMap::zoomIn); - g_lua.bindClassMemberFunction("zoomOut", &UIMap::zoomOut); + g_lua.bindClassMemberFunction("getMaxZoomIn", &UIMap::getMaxZoomIn); + g_lua.bindClassMemberFunction("getMaxZoomOut", &UIMap::getMaxZoomOut); + g_lua.bindClassMemberFunction("getZoom", &UIMap::getZoom); } diff --git a/src/otclient/ui/uimap.cpp b/src/otclient/ui/uimap.cpp index 5df67881..9838541a 100644 --- a/src/otclient/ui/uimap.cpp +++ b/src/otclient/ui/uimap.cpp @@ -32,6 +32,10 @@ UIMap::UIMap() { m_dragable = true; m_mapView = MapViewPtr(new MapView); + m_zoom = m_mapView->getVisibleDimension().height(); + m_aspectRatio = 0.0f; + m_maxZoomIn = 3; + m_maxZoomOut = 512; g_map.addMapView(m_mapView); } @@ -51,56 +55,48 @@ void UIMap::drawSelf() m_mapView->draw(m_mapRect); } -void UIMap::zoomIn() +bool UIMap::setZoom(int zoom) { - int dimensionHeight = m_mapView->getVisibleDimension().height() * 0.99; - if(dimensionHeight == m_mapView->getVisibleDimension().height()) - dimensionHeight -= 1; - if(dimensionHeight % 2 == 0) - dimensionHeight -= 1; - int dimensionWidth = dimensionHeight * getSize().ratio(); - if(dimensionWidth % 2 == 0) - dimensionWidth -= 1; - - m_mapView->setVisibleDimension(Size(dimensionWidth, dimensionHeight)); - - Rect mapRect = getClippingRect().expanded(-1); - Size mapSize = m_mapView->getVisibleSize(); - mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); - - m_mapRect.resize(mapSize); - m_mapRect.moveCenter(m_rect.center()); + //TODO + return false; } -void UIMap::zoomOut() +bool UIMap::zoomIn() { - int dimensionHeight = m_mapView->getVisibleDimension().height() * 1.01; - if(dimensionHeight == m_mapView->getVisibleDimension().height()) - dimensionHeight += 1; - if(dimensionHeight % 2 == 0) - dimensionHeight += 1; - int dimensionWidth = dimensionHeight * getSize().ratio(); - if(dimensionWidth % 2 == 0) - dimensionWidth += 1; + int delta = 2; + if(m_zoom - delta <= m_maxZoomIn) + return false; - m_mapView->setVisibleDimension(Size(dimensionWidth, dimensionHeight)); + m_zoom -= delta; + updateVisibleDimension(); + return true; +} - Rect mapRect = getClippingRect().expanded(-1); - Size mapSize = m_mapView->getVisibleSize(); - mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); +bool UIMap::zoomOut() +{ + int delta = 2; + if(m_zoom + delta >= m_maxZoomOut) + return false; - m_mapRect.resize(mapSize); - m_mapRect.moveCenter(m_rect.center()); + m_zoom += 2; + updateVisibleDimension(); + return true; } -void UIMap::followCreature(const CreaturePtr& creature) +void UIMap::setVisibleDimension(const Size& visibleDimension) { - m_mapView->followCreature(creature); + m_mapView->setVisibleDimension(visibleDimension); + + if(m_aspectRatio != 0.0f) + m_aspectRatio = visibleDimension.ratio(); } -void UIMap::setCameraPosition(const Position& pos) +void UIMap::setKeepAspectRatio(bool enable) { - m_mapView->setCameraPosition(pos); + if(enable) + m_aspectRatio = getVisibleDimension().ratio(); + else + m_aspectRatio = 0.0f; } TilePtr UIMap::getTile(const Point& mousePos) @@ -112,14 +108,61 @@ TilePtr UIMap::getTile(const Point& mousePos) return m_mapView->getTile(mousePos, m_mapRect); } +void UIMap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) +{ + UIWidget::onStyleApply(styleName, styleNode); + for(const OTMLNodePtr& node : styleNode->children()) { + if(node->tag() == "multifloor") + setMultifloor(node->value()); + else if(node->tag() == "auto-view-mode") + setAutoViewMode(node->value()); + else if(node->tag() == "draw-texts") + setDrawTexts(node->value()); + else if(node->tag() == "draw-minimap-colors") + setDrawMinimapColors(node->value()); + else if(node->tag() == "animated") + setAnimated(node->value()); + } +} + void UIMap::onGeometryChange(const Rect& oldRect, const Rect& newRect) { UIWidget::onGeometryChange(oldRect, newRect); + updateMapSize(); +} - Rect mapRect = getClippingRect().expanded(-1); - Size mapSize = m_mapView->getVisibleSize(); - mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); +void UIMap::updateVisibleDimension() +{ + int dimensionHeight = m_zoom; + if(dimensionHeight % 2 == 0) + dimensionHeight += 1; + int dimensionWidth = m_zoom * m_mapRect.size().ratio(); + if(dimensionWidth % 2 == 0) + dimensionWidth += 1; + + m_mapView->setVisibleDimension(Size(dimensionWidth, dimensionHeight)); + + if(m_aspectRatio != 0.0f) + updateMapSize(); +} + +void UIMap::updateMapSize() +{ + Rect clippingRect = getClippingRect(); + Size mapSize; + if(m_aspectRatio != 0.0f) { + Rect mapRect = clippingRect.expanded(-1); + mapSize = Size(m_aspectRatio*m_zoom, m_zoom); + mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); + } else { + mapSize = clippingRect.expanded(-1).size(); + } m_mapRect.resize(mapSize); - m_mapRect.moveCenter(newRect.center()); + m_mapRect.moveCenter(clippingRect.center()); + m_mapView->optimizeForSize(mapSize); + + if(m_aspectRatio == 0.0f) + updateVisibleDimension(); } + diff --git a/src/otclient/ui/uimap.h b/src/otclient/ui/uimap.h index c5e512a5..2cb0ff59 100644 --- a/src/otclient/ui/uimap.h +++ b/src/otclient/ui/uimap.h @@ -27,6 +27,8 @@ #include #include +#include + class UIMap : public UIWidget { public: @@ -35,19 +37,55 @@ public: void drawSelf(); - void zoomIn(); - void zoomOut(); - void followCreature(const CreaturePtr& creature); - void setCameraPosition(const Position& pos); + bool setZoom(int zoom); + bool zoomIn(); + bool zoomOut(); + void followCreature(const CreaturePtr& creature) { m_mapView->followCreature(creature); } + + void setCameraPosition(const Position& pos) { m_mapView->setCameraPosition(pos); } + void setMaxZoomIn(int maxZoomIn) { m_maxZoomIn = maxZoomIn; } + void setMaxZoomOut(int maxZoomOut) { m_maxZoomOut = maxZoomOut; } + void setMultifloor(bool enable) { m_mapView->setMultifloor(enable); } + void setVisibleDimension(const Size& visibleDimension); + void setViewMode(MapView::ViewMode viewMode) { m_mapView->setViewMode(viewMode); } + void setAutoViewMode(bool enable) { m_mapView->setAutoViewMode(enable); } + void setDrawFlags(Otc::DrawFlags drawFlags) { m_mapView->setDrawFlags(drawFlags); } + void setDrawTexts(bool enable) { m_mapView->setDrawTexts(enable); } + void setDrawMinimapColors(bool enable) { m_mapView->setDrawMinimapColors(enable); } + void setAnimated(bool enable) { m_mapView->setAnimated(enable); } + void setKeepAspectRatio(bool enable); + bool isMultifloor() { return m_mapView->isMultifloor(); } + bool isAutoViewModeEnabled() { return m_mapView->isAutoViewModeEnabled(); } + bool isDrawingTexts() { return m_mapView->isDrawingTexts(); } + bool isDrawingMinimapColors() { return m_mapView->isDrawingMinimapColors(); } + bool isAnimating() { return m_mapView->isAnimating(); } + float isKeepAspectRatioEnabled() { return m_aspectRatio != 0.0f; } + + Size getVisibleDimension() { return m_mapView->getVisibleDimension(); } + MapView::ViewMode getViewMode() { return m_mapView->getViewMode(); } + CreaturePtr getFollowingCreature() { return m_mapView->getFollowingCreature(); } + Otc::DrawFlags getDrawFlags() { return m_mapView->getDrawFlags(); } + Position getCameraPosition() { return m_mapView->getCameraPosition(); } TilePtr getTile(const Point& mousePos); + int getMaxZoomIn() { return m_maxZoomIn; } + int getMaxZoomOut() { return m_maxZoomOut; } + int getZoom() { return m_zoom; } protected: + virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode); virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect); private: + void updateVisibleDimension(); + void updateMapSize(); + + int m_zoom; MapViewPtr m_mapView; Rect m_mapRect; + float m_aspectRatio; + int m_maxZoomIn; + int m_maxZoomOut; }; #endif