From ae731ddefc727b4dbf78d5157361f9a86c1bda02 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sun, 20 Jan 2013 21:17:56 -0200 Subject: [PATCH] Rework minimap rendering --- modules/game_interface/gameinterface.lua | 20 +-- modules/game_minimap/minimap.lua | 33 ++-- modules/game_minimap/minimap.otui | 3 +- src/client/CMakeLists.txt | 4 + src/client/client.cpp | 3 + src/client/creature.cpp | 2 +- src/client/declarations.h | 2 + src/client/luafunctions.cpp | 22 ++- src/client/map.cpp | 13 +- src/client/map.h | 2 +- src/client/mapio.cpp | 2 + src/client/mapview.cpp | 86 ++-------- src/client/mapview.h | 4 - src/client/minimap.cpp | 196 +++++++++++++++++++++++ src/client/minimap.h | 76 ++++++--- src/client/uimap.cpp | 2 - src/client/uimap.h | 2 - src/client/uiminimap.cpp | 108 +++++++++++++ src/client/uiminimap.h | 69 ++++++++ src/framework/graphics/image.h | 2 + src/framework/graphics/texture.cpp | 25 +-- src/framework/graphics/texture.h | 1 + src/framework/util/size.h | 2 +- 23 files changed, 531 insertions(+), 148 deletions(-) create mode 100644 src/client/uiminimap.cpp create mode 100644 src/client/uiminimap.h diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index 2da23331..33ff56de 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -111,7 +111,7 @@ function terminate() end function onGameStart() - logoutButton:setTooltip('Logout') + logoutButton:setTooltip(tr('Logout')) show() -- open tibia has delay in auto walking @@ -121,7 +121,7 @@ function onGameStart() end function onGameEnd() - logoutButton:setTooltip('Exit') + logoutButton:setTooltip(tr('Exit')) hide() end @@ -153,7 +153,7 @@ function hide() end function onLoginAdvice(message) - displayInfoBox("For Your Information", message) + displayInfoBox(tr("For Your Information"), message) end function forceExit() @@ -170,10 +170,10 @@ function tryExit() local logoutFunc = function() logout() exitWindow:destroy() exitWindow = nil end local cancelFunc = function() exitWindow:destroy() exitWindow = nil end - exitWindow = displayGeneralBox('Exit', tr("If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."), - { { text='Force Exit', callback=exitFunc }, - { text='Logout', callback=logoutFunc }, - { text='Cancel', callback=cancelFunc }, + exitWindow = displayGeneralBox(tr('Exit'), tr("If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."), + { { text=tr('Force Exit'), callback=exitFunc }, + { text=tr('Logout'), callback=logoutFunc }, + { text=tr('Cancel'), callback=cancelFunc }, anchor=AnchorHorizontalCenter }, logoutFunc, cancelFunc) return true @@ -198,9 +198,9 @@ function tryLogout() local yesCallback = function() logout() logoutWindow:destroy() logoutWindow=nil end local noCallback = function() logoutWindow:destroy() logoutWindow=nil end - logoutWindow = displayGeneralBox('Logout', tr('Are you sure you want to logout?'), { - { text='Yes', callback=yesCallback }, - { text='No', callback=noCallback }, + logoutWindow = displayGeneralBox(tr('Logout'), tr('Are you sure you want to logout?'), { + { text=tr('Yes'), callback=yesCallback }, + { text=tr('No'), callback=noCallback }, anchor=AnchorHorizontalCenter}, yesCallback, noCallback) end diff --git a/modules/game_minimap/minimap.lua b/modules/game_minimap/minimap.lua index e5049e01..581065ac 100644 --- a/modules/game_minimap/minimap.lua +++ b/modules/game_minimap/minimap.lua @@ -1,4 +1,4 @@ -DEFAULT_ZOOM = 60 +DEFAULT_ZOOM = 0 MAX_FLOOR_UP = 0 MAX_FLOOR_DOWN = 15 @@ -32,16 +32,11 @@ function init() minimapWindow = g_ui.loadUI('minimap', modules.game_interface.getRightPanel()) minimapWindow:setContentMinimumHeight(64) - minimapWindow:setContentMaximumHeight(256) + --minimapWindow:setContentMaximumHeight(256) minimapWidget = minimapWindow:recursiveGetChildById('minimap') g_mouse.bindAutoPress(minimapWidget, compassClick, nil, MouseLeftButton) - - minimapWidget:setAutoViewMode(false) - minimapWidget:setViewMode(1) -- mid view - minimapWidget:setDrawMinimapColors(true) - minimapWidget:setMultifloor(false) - minimapWidget:setKeepAspectRatio(false) + minimapWidget.onMouseRelease = onMinimapMouseRelease minimapWidget.onMouseWheel = onMinimapMouseWheel flagsPanel = minimapWindow:recursiveGetChildById('flagsPanel') @@ -204,11 +199,11 @@ end function getMapArea() return minimapWidget:getPosition( { x = 1 + minimapWidget:getX(), y = 1 + minimapWidget:getY() } ), - minimapWidget:getPosition( { x = -2 + minimapWidget:getWidth() + minimapWidget:getX(), y = -2 + minimapWidget:getHeight() + minimapWidget:getY() } ) + minimapWidget:getPosition( { x = -2 + minimapWidget:getWidth() + minimapWidget:getX(), y = -2 + minimapWidget:getHeight() + minimapWidget:getY() } ) end function isFlagVisible(flag, firstPosition, lastPosition) - return flag.version == g_game.getProtocolVersion() and (minimapWidget:getZoom() >= 30 and minimapWidget:getZoom() <= 150) and flag.position.x >= firstPosition.x and flag.position.x <= lastPosition.x and flag.position.y >= firstPosition.y and flag.position.y <= lastPosition.y and flag.position.z == firstPosition.z + return flag.version == g_game.getProtocolVersion() and (minimapWidget:getZoom() >= 0 and minimapWidget:getZoom() <= 2) and flag.position.x >= firstPosition.x and flag.position.x <= lastPosition.x and flag.position.y >= firstPosition.y and flag.position.y <= lastPosition.y and flag.position.z == firstPosition.z end function updateMapFlag(id) @@ -314,7 +309,7 @@ function compassClick(self, mousePos, mouseButton, elapsed) dx = dx/radius dy = dy/radius - local speed = math.ceil(minimapWidget:getZoom()/22) + local speed = math.ceil((1.0 / minimapWidget:getScale()) * 3) if dx > 0.5 then movex = speed end if dx < -0.5 then movex = -speed end if dy > 0.5 then movey = -speed end @@ -327,12 +322,12 @@ function compassClick(self, mousePos, mouseButton, elapsed) updateMapFlags() end -function miniMapZoomIn(zoom) - minimapWidget:setZoom(math.max(minimapWidget:getMaxZoomIn(), minimapWidget:getZoom()-zoom)) +function miniMapZoomIn() + minimapWidget:zoomIn() end -function miniMapZoomOut(zoom) - minimapWidget:setZoom(math.min(minimapWidget:getMaxZoomOut(), minimapWidget:getZoom()+zoom)) +function miniMapZoomOut() + minimapWidget:zoomOut() end function minimapFloorUp(floors) @@ -363,9 +358,9 @@ end function onButtonClick(id) if id == "zoomIn" then - miniMapZoomIn(20) + miniMapZoomIn() elseif id == "zoomOut" then - miniMapZoomOut(20) + miniMapZoomOut() elseif id == "floorUp" then minimapFloorUp(1) elseif id == "floorDown" then @@ -403,9 +398,9 @@ function onMinimapMouseWheel(self, mousePos, direction) local keyboardModifiers = g_keyboard.getModifiers() if direction == MouseWheelUp and keyboardModifiers == KeyboardNoModifier then - miniMapZoomIn(10) + miniMapZoomIn() elseif direction == MouseWheelDown and keyboardModifiers == KeyboardNoModifier then - miniMapZoomOut(10) + miniMapZoomOut() elseif direction == MouseWheelDown and keyboardModifiers == KeyboardCtrlModifier then minimapFloorUp(1) elseif direction == MouseWheelUp and keyboardModifiers == KeyboardCtrlModifier then diff --git a/modules/game_minimap/minimap.otui b/modules/game_minimap/minimap.otui index 223e6def..8bd4dc48 100644 --- a/modules/game_minimap/minimap.otui +++ b/modules/game_minimap/minimap.otui @@ -47,9 +47,10 @@ MiniWindow size: 14 14 MiniWindowContents - UIMap + UIMinimap id: minimap anchors.fill: parent + cross: true Panel id: flagsPanel diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index a356e9a4..d7e8ee2f 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -44,6 +44,8 @@ set(client_SOURCES ${client_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/mapio.cpp ${CMAKE_CURRENT_LIST_DIR}/mapview.cpp ${CMAKE_CURRENT_LIST_DIR}/mapview.h + ${CMAKE_CURRENT_LIST_DIR}/minimap.cpp + ${CMAKE_CURRENT_LIST_DIR}/minimap.h ${CMAKE_CURRENT_LIST_DIR}/lightview.cpp ${CMAKE_CURRENT_LIST_DIR}/lightview.h ${CMAKE_CURRENT_LIST_DIR}/missile.cpp @@ -92,6 +94,8 @@ set(client_SOURCES ${client_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/uiitem.h ${CMAKE_CURRENT_LIST_DIR}/uimap.cpp ${CMAKE_CURRENT_LIST_DIR}/uimap.h + ${CMAKE_CURRENT_LIST_DIR}/uiminimap.cpp + ${CMAKE_CURRENT_LIST_DIR}/uiminimap.h ${CMAKE_CURRENT_LIST_DIR}/uiprogressrect.cpp ${CMAKE_CURRENT_LIST_DIR}/uiprogressrect.h diff --git a/src/client/client.cpp b/src/client/client.cpp index bf01fef1..374ba21f 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -28,6 +28,7 @@ #include "map.h" #include "shadermanager.h" #include "spritemanager.h" +#include "minimap.h" #include Client g_client; @@ -38,6 +39,7 @@ void Client::init(std::vector& args) registerLuaFunctions(); g_map.init(); + g_minimap.init(); g_game.init(); g_shaders.init(); g_things.init(); @@ -84,6 +86,7 @@ void Client::terminate() g_creatures.terminate(); g_game.terminate(); g_map.terminate(); + g_minimap.terminate(); g_things.terminate(); g_sprites.terminate(); g_shaders.terminate(); diff --git a/src/client/creature.cpp b/src/client/creature.cpp index c708a2ac..ca2b66cc 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -502,7 +502,7 @@ void Creature::updateWalkingTile() // recache visible tiles in map views if(newWalkingTile->isEmpty()) - g_map.notificateTileUpdateToMapViews(newWalkingTile->getPosition()); + g_map.notificateTileUpdate(newWalkingTile->getPosition()); } m_walkingTile = newWalkingTile; } diff --git a/src/client/declarations.h b/src/client/declarations.h index a6c09b21..c0aa3fed 100644 --- a/src/client/declarations.h +++ b/src/client/declarations.h @@ -92,11 +92,13 @@ typedef stdext::shared_object_ptr ProtocolLoginPtr; class UIItem; class UICreature; class UIMap; +class UIMinimap; class UIProgressRect; typedef stdext::shared_object_ptr UIItemPtr; typedef stdext::shared_object_ptr UICreaturePtr; typedef stdext::shared_object_ptr UIMapPtr; +typedef stdext::shared_object_ptr UIMinimapPtr; typedef stdext::shared_object_ptr UIProgressRectPtr; #endif diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index 63813986..4f00d85f 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -43,6 +43,7 @@ #include "uiitem.h" #include "uicreature.h" #include "uimap.h" +#include "uiminimap.h" #include "uiprogressrect.h" #include "outfit.h" @@ -548,7 +549,6 @@ void Client::registerLuaFunctions() 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("setDrawLights", &UIMap::setDrawLights); g_lua.bindClassMemberFunction("setAnimated", &UIMap::setAnimated); g_lua.bindClassMemberFunction("setKeepAspectRatio", &UIMap::setKeepAspectRatio); @@ -557,7 +557,6 @@ void Client::registerLuaFunctions() 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("isDrawingLights", &UIMap::isDrawingLights); g_lua.bindClassMemberFunction("isAnimating", &UIMap::isAnimating); g_lua.bindClassMemberFunction("isKeepAspectRatioEnabled", &UIMap::isKeepAspectRatioEnabled); @@ -574,6 +573,25 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("getMapShader", &UIMap::getMapShader); g_lua.bindClassMemberFunction("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight); + g_lua.registerClass(); + g_lua.bindClassStaticFunction("create", []{ return UIMinimapPtr(new UIMinimap); }); + g_lua.bindClassMemberFunction("zoomIn", &UIMinimap::zoomIn); + g_lua.bindClassMemberFunction("zoomOut", &UIMinimap::zoomOut); + g_lua.bindClassMemberFunction("setZoom", &UIMinimap::setZoom); + g_lua.bindClassMemberFunction("setMixZoom", &UIMinimap::setMinZoom); + g_lua.bindClassMemberFunction("setMaxZoom", &UIMinimap::setMaxZoom); + g_lua.bindClassMemberFunction("setCameraPosition", &UIMinimap::setCameraPosition); + g_lua.bindClassMemberFunction("setCross", &UIMinimap::setCross); + g_lua.bindClassMemberFunction("followCreature", &UIMinimap::followCreature); + g_lua.bindClassMemberFunction("getPosition", &UIMinimap::getPosition); + g_lua.bindClassMemberFunction("getCameraPosition", &UIMinimap::getCameraPosition); + g_lua.bindClassMemberFunction("getFollowingCreature", &UIMinimap::getFollowingCreature); + g_lua.bindClassMemberFunction("getMinZoom", &UIMinimap::getMinZoom); + g_lua.bindClassMemberFunction("getMaxZoom", &UIMinimap::getMaxZoom); + g_lua.bindClassMemberFunction("getZoom", &UIMinimap::getZoom); + g_lua.bindClassMemberFunction("getCross", &UIMinimap::getCross); + g_lua.bindClassMemberFunction("getScale", &UIMinimap::getScale); + g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return UIProgressRectPtr(new UIProgressRect); } ); g_lua.bindClassMemberFunction("setPercent", &UIProgressRect::setPercent); diff --git a/src/client/map.cpp b/src/client/map.cpp index a6d25d17..72127d21 100644 --- a/src/client/map.cpp +++ b/src/client/map.cpp @@ -28,6 +28,7 @@ #include "missile.h" #include "statictext.h" #include "mapview.h" +#include "minimap.h" #include #include @@ -57,10 +58,14 @@ void Map::removeMapView(const MapViewPtr& mapView) m_mapViews.erase(it); } -void Map::notificateTileUpdateToMapViews(const Position& pos) +void Map::notificateTileUpdate(const Position& pos) { + if(!pos.isMapPosition()) + return; + for(const MapViewPtr& mapView : m_mapViews) mapView->onTileUpdate(pos); + g_minimap.updateTile(pos, getTile(pos)); } void Map::clean() @@ -159,7 +164,7 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) thing->onAppear(); } - notificateTileUpdateToMapViews(pos); + notificateTileUpdate(pos); } ThingPtr Map::getThing(const Position& pos, int stackPos) @@ -174,7 +179,7 @@ bool Map::removeThing(const ThingPtr& thing) if(!thing) return false; - notificateTileUpdateToMapViews(thing->getPosition()); + notificateTileUpdate(thing->getPosition()); if(thing->isMissile()) { MissilePtr missile = thing->static_self_cast(); @@ -288,7 +293,7 @@ void Map::cleanTile(const Position& pos) if(tile->canErase()) block.remove(pos); - notificateTileUpdateToMapViews(pos); + notificateTileUpdate(pos); } } for(auto it = m_staticTexts.begin();it != m_staticTexts.end();) { diff --git a/src/client/map.h b/src/client/map.h index 903c8fbe..82dc3c52 100644 --- a/src/client/map.h +++ b/src/client/map.h @@ -139,7 +139,7 @@ public: void addMapView(const MapViewPtr& mapView); void removeMapView(const MapViewPtr& mapView); - void notificateTileUpdateToMapViews(const Position& pos); + void notificateTileUpdate(const Position& pos); bool loadOtcm(const std::string& fileName); void saveOtcm(const std::string& fileName); diff --git a/src/client/mapio.cpp b/src/client/mapio.cpp index dae3c34b..d66fb89c 100644 --- a/src/client/mapio.cpp +++ b/src/client/mapio.cpp @@ -440,6 +440,8 @@ bool Map::loadOtcm(const std::string& fileName) if(item->isValid()) tile->addThing(item, stackPos++); } + + g_map.notificateTileUpdate(pos); } fin->close(); diff --git a/src/client/mapview.cpp b/src/client/mapview.cpp index 42dfd8c3..1dac59c9 100644 --- a/src/client/mapview.cpp +++ b/src/client/mapview.cpp @@ -130,19 +130,10 @@ void MapView::draw(const Rect& rect) else ++it; - if(!m_drawMinimapColors) - tile->draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags, m_lightView.get()); - else { - uint8 c = tile->getMinimapColorByte(); - if(c == 0) - continue; - - g_painter->setColor(Color::from8bit(c)); - g_painter->drawFilledRect(Rect(transformPositionTo2D(tilePos, cameraPosition), tileSize)); - } + tile->draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags, m_lightView.get()); } - if(drawFlags & Otc::DrawMissiles && !m_drawMinimapColors) { + if(drawFlags & Otc::DrawMissiles) { for(const MissilePtr& missile : g_map.getFloorMissiles(z)) { missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), scaleFactor, drawFlags & Otc::DrawAnimations, m_lightView.get()); } @@ -283,36 +274,6 @@ void MapView::draw(const Rect& rect) p += rect.topLeft(); animatedText->drawText(p, rect); } - } else if(m_viewMode > NEAR_VIEW) { - // draw a cross in the center instead of our creature - /* - Known Issue: Changing Z axis causes the cross to go off a little bit. - */ - Rect vRect(0, 0, 2, 10); - Rect hRect(0, 0, 10, 2); - g_painter->setColor(Color::white); - - if(!m_follow && m_followingCreature) - { - Position pos = m_followingCreature->getPosition(); - Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset; - p.x = p.x * horizontalStretchFactor; - p.y = p.y * verticalStretchFactor; - p += rect.topLeft(); - - vRect.setX(p.x); vRect.setY(p.y - 4); - hRect.setX(p.x - 4); hRect.setY(p.y); - - hRect.setWidth(10); hRect.setHeight(2); - vRect.setWidth(2); vRect.setHeight(10); - } - else { - vRect.moveCenter(rect.center()); - hRect.moveCenter(rect.center()); - } - - g_painter->drawFilledRect(vRect); - g_painter->drawFilledRect(hRect); } } @@ -453,25 +414,20 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized int tileSize = 0; Size bufferSize; - if(!m_drawMinimapColors) { - int possiblesTileSizes[] = {1,2,4,8,16,32}; - for(int candidateTileSize : possiblesTileSizes) { - bufferSize = (visibleDimension + Size(3,3)) * candidateTileSize; - if(bufferSize.width() > g_graphics.getMaxTextureSize() || bufferSize.height() > g_graphics.getMaxTextureSize()) - break; + int possiblesTileSizes[] = {1,2,4,8,16,32}; + 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; - } + tileSize = candidateTileSize; + if(optimizedSize.width() < bufferSize.width() - 3*candidateTileSize && optimizedSize.height() < bufferSize.height() - 3*candidateTileSize) + break; + } - if(tileSize == 0) { - g_logger.traceError("reached max zoom out"); - return; - } - } else { - tileSize = 1; - bufferSize = visibleDimension + Size(3,3); + if(tileSize == 0) { + g_logger.traceError("reached max zoom out"); + return; } Size drawDimension = visibleDimension + Size(3,3); @@ -518,8 +474,7 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized void MapView::onTileUpdate(const Position& pos) { - if(!m_drawMinimapColors) - requestVisibleTilesCacheUpdate(); + requestVisibleTilesCacheUpdate(); } void MapView::onMapCenterChange(const Position& pos) @@ -682,17 +637,6 @@ Position MapView::getCameraPosition() return m_customCameraPosition; } -void MapView::setDrawMinimapColors(bool enable) -{ - if(m_drawMinimapColors == enable) - return; - m_drawMinimapColors = enable; - updateGeometry(m_visibleDimension, m_optimizedSize); - requestVisibleTilesCacheUpdate(); - m_smooth = !enable; - m_framebuffer->setSmooth(m_smooth); -} - void MapView::setShader(const PainterShaderProgramPtr& shader, float fadein, float fadeout) { if((m_shader == shader && m_shaderSwitchDone) || (m_nextShader == shader && !m_shaderSwitchDone)) diff --git a/src/client/mapview.h b/src/client/mapview.h index 8b0cc8a8..95b06049 100644 --- a/src/client/mapview.h +++ b/src/client/mapview.h @@ -98,9 +98,6 @@ public: void setDrawTexts(bool enable) { m_drawTexts = enable; } bool isDrawingTexts() { return m_drawTexts; } - void setDrawMinimapColors(bool enable); - bool isDrawingMinimapColors() { return m_drawMinimapColors; } - void setAnimated(bool animated) { m_animated = animated; requestVisibleTilesCacheUpdate(); } bool isAnimating() { return m_animated; } @@ -139,7 +136,6 @@ private: stdext::boolean m_autoViewMode; stdext::boolean m_drawTexts; stdext::boolean m_smooth; - stdext::boolean m_drawMinimapColors; stdext::boolean m_drawLights; stdext::boolean m_follow; std::vector m_cachedVisibleTiles; diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 47b46047..63b6282f 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -22,4 +22,200 @@ #include "minimap.h" +#include "tile.h" +#include +#include +#include +#include +#include +Minimap g_minimap; + +void MinimapBlock::updateImage() +{ + if(!m_image) + m_image = ImagePtr(new Image(Size(MMBLOCK_SIZE, MMBLOCK_SIZE))); + else + m_image->resize(Size(MMBLOCK_SIZE, MMBLOCK_SIZE)); + + for(int x=0;xsetPixel(x, y, Color::from8bit(getTile(x, y).color).rgba()); +} + +void MinimapBlock::updateTexture() +{ + if(!m_image) + return; + + if(!m_texture) { + m_texture = TexturePtr(new Texture(m_image, true)); + } else { + m_texture->uploadPixels(m_image, true); + } +} + +void MinimapBlock::clean() +{ + m_tiles.fill(MinimapTile()); + m_image.reset(); + m_texture.reset(); + m_shouldDraw = false; + m_mustUpdate = false; +} + +void MinimapBlock::update() +{ + if(!m_mustUpdate) + return; + + if(m_shouldDraw) { + updateImage(); + updateTexture(); + } + + m_mustUpdate = false; +} + +void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile) +{ + if(!(m_tiles[getTileIndex(x,y)] == tile)) { + m_tiles[getTileIndex(x,y)] = tile; + + if(tile.color != 0) + m_shouldDraw = true; + m_mustUpdate = true; + } +} + +void Minimap::init() +{ + +} + +void Minimap::terminate() +{ + clean(); +} + +void Minimap::clean() +{ + for(int i=0;i<=Otc::MAX_Z;++i) + m_tileBlocks[i].clear(); +} + +void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scale) +{ + if(screenRect.isEmpty()) + return; + + if(MMBLOCK_SIZE*scale <= 1) + return; + + Size mapSize = screenRect.size() / scale; + while(mapSize.width() > 8192 || mapSize.height() > 8192) { + scale *= 2; + mapSize = screenRect.size() / scale; + } + Rect mapRect(0, 0, mapSize); + mapRect.moveCenter(Point(mapCenter.x, mapCenter.y)); + + g_painter->saveState(); + g_painter->setColor(Color::black); + g_painter->drawFilledRect(screenRect); + g_painter->resetColor(); + g_painter->setClipRect(screenRect); + g_painter->translate(screenRect.topLeft()); + + Point p = getBlockOffset(mapRect.topLeft() - Point(1,1)); + g_painter->translate(-(mapRect.topLeft() - p)*scale); + + if(scale > 1.0f) + g_painter->translate(Point(1,1) * scale * 0.5f); + + for(int y = p.y, ys = 0;y<=mapRect.bottom();y += MMBLOCK_SIZE, ys += MMBLOCK_SIZE*scale) { + if(y < 0 || y >= 65536 - MMBLOCK_SIZE) + continue; + + for(int x = p.x, xs = 0;x<=mapRect.right();x += MMBLOCK_SIZE, xs += MMBLOCK_SIZE*scale) { + if(x < 0 || x >= 65536 - MMBLOCK_SIZE) + continue; + + MinimapBlock& block = getBlock(Position(x, y, mapCenter.z)); + block.update(); + + if(block.shouldDraw()) { + Rect src(0, 0, MMBLOCK_SIZE, MMBLOCK_SIZE); + Rect dest(Point(xs,ys), src.size() * scale); + const TexturePtr& tex = block.getTexture(); + + tex->setSmooth(scale < 1.0f); + g_painter->drawTexturedRect(dest, tex, src); + } + } + } + + g_painter->restoreSavedState(); +} + +Position Minimap::getPosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale) +{ + if(screenRect.isEmpty()) + return Position(); + + if(MMBLOCK_SIZE*scale <= 1) + return Position(); + + Position pos(mapCenter); + + Size mapSize = screenRect.size() / scale; + while(mapSize.width() > 8192 || mapSize.height() > 8192) { + scale *= 2; + mapSize = screenRect.size() / scale; + } + Rect mapRect(0, 0, mapSize); + mapRect.moveCenter(Point(mapCenter.x, mapCenter.y)); + + Point p = (point - screenRect.topLeft() - Point(1,1) * scale * 0.5f)/scale + mapRect.topLeft(); + + pos.x = p.x; + pos.y = p.y; + + return pos; +} + +void Minimap::updateTile(const Position& pos, const TilePtr& tile) +{ + MinimapBlock& block = getBlock(pos); + Point offsetPos = getBlockOffset(Point(pos.x, pos.y)); + + MinimapTile minimapTile; + if(tile) { + minimapTile.color = tile->getMinimapColorByte(); + if(tile->isWalkable()) + minimapTile.flags |= MinimapTileWalkable; + if(tile->isPathable()) + minimapTile.flags |= MinimapTilePathable; + if(tile->changesFloor()) + minimapTile.flags |= MinimapTileChangesFloor; + } + + block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile); +} + +bool Minimap::checkTileProperty(const Position& pos, int flags) +{ + MinimapBlock& block = getBlock(pos); + Point offsetPos = getBlockOffset(Point(pos.x, pos.y)); + return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y).flags & flags; +} + +void Minimap::loadOtmm(const std::string& fileName) +{ + +} + +void Minimap::saveOtmm(const std::string& fileName) +{ + +} diff --git a/src/client/minimap.h b/src/client/minimap.h index fe91aa07..ef4eea62 100644 --- a/src/client/minimap.h +++ b/src/client/minimap.h @@ -24,19 +24,51 @@ #ifndef MINIMAP_H #define MINIMAP_H -#include "global.h" -#include -/* +#include "declarations.h" +#include + enum { - MINIMAP_AREA_SIZE = 32 + MMBLOCK_SIZE = 64 +}; + +enum MinimapTileFlags { + MinimapTilePathable = 1, + MinimapTileWalkable = 2, + MinimapTileChangesFloor = 4 }; -struct MinimapArea +#pragma pack(push,1) // disable memory alignment +struct MinimapTile { - ImagePtr img; - TexturePtr tex; - uint8 colors[MINIMAP_AREA_SIZE][MINIMAP_AREA_SIZE]; - stdext::boolean mustUpdate; + MinimapTile() : flags(0), color(0) { } + uint8 flags; + uint8 color; + + bool operator==(const MinimapTile& other) { return color == other.color && flags == other.flags; } +}; +#pragma pack(pop) + +class MinimapBlock +{ +public: + void updateImage(); + void updateTexture(); + void clean(); + void update(); + void updateTile(int x, int y, const MinimapTile& tile); + MinimapTile& getTile(int x, int y) { return m_tiles[getTileIndex(x,y)]; } + void resetTile(int x, int y) { m_tiles[getTileIndex(x,y)] = MinimapTile(); } + uint getTileIndex(int x, int y) { return ((y % MMBLOCK_SIZE) * MMBLOCK_SIZE) + (x % MMBLOCK_SIZE); } + const TexturePtr& getTexture() { return m_texture; } + std::array getTiles() { return m_tiles; } + bool shouldDraw() { return m_shouldDraw; } + +private: + ImagePtr m_image; + TexturePtr m_texture; + stdext::boolean m_shouldDraw; + std::array m_tiles; + stdext::boolean m_mustUpdate; }; class Minimap @@ -46,21 +78,25 @@ public: void init(); void terminate(); - void loadOtmm(); - void saveOtmm(); + void clean(); - void updateTile(const Position& pos, uint8 color); + void draw(const Rect& screenRect, const Position& mapCenter, float scale); + Position getPosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale); -private: + void updateTile(const Position& pos, const TilePtr& tile); + bool checkTileProperty(const Position& pos, int flags); - struct MinimaAreaHasher : std::unary_function { - std::size_t operator()(const Position& pos) const { - return ((pos.x/MINIMAP_AREA_SIZE) * 0x8000 + (pos.y/MINIMAP_AREA_SIZE)) * 16 + pos.z; - } - }; - std::unordered_map m_areas; + void loadOtmm(const std::string& fileName); + void saveOtmm(const std::string& fileName); + +private: + MinimapBlock& getBlock(const Position& pos) { return m_tileBlocks[pos.z][getBlockIndex(pos)]; } + Point getBlockOffset(const Point& pos) { return Point(pos.x - pos.x % MMBLOCK_SIZE, + pos.y - pos.y % MMBLOCK_SIZE); } + uint getBlockIndex(const Position& pos) { return ((pos.y / MMBLOCK_SIZE) * (65536 / MMBLOCK_SIZE)) + (pos.x / MMBLOCK_SIZE); } + std::unordered_map m_tileBlocks[Otc::MAX_Z+1]; }; extern Minimap g_minimap; -*/ + #endif diff --git a/src/client/uimap.cpp b/src/client/uimap.cpp index ee7b4fdf..6b2e38e2 100644 --- a/src/client/uimap.cpp +++ b/src/client/uimap.cpp @@ -179,8 +179,6 @@ void UIMap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleN 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() == "draw-lights") setDrawLights(node->value()); else if(node->tag() == "animated") diff --git a/src/client/uimap.h b/src/client/uimap.h index 93a36072..b36543bf 100644 --- a/src/client/uimap.h +++ b/src/client/uimap.h @@ -51,7 +51,6 @@ public: 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 setDrawLights(bool enable) { m_mapView->setDrawLights(enable); } void setAnimated(bool enable) { m_mapView->setAnimated(enable); } void setKeepAspectRatio(bool enable); @@ -61,7 +60,6 @@ public: 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 isDrawingLights() { return m_mapView->isDrawingLights(); } bool isAnimating() { return m_mapView->isAnimating(); } bool isKeepAspectRatioEnabled() { return m_aspectRatio != 0.0f; } diff --git a/src/client/uiminimap.cpp b/src/client/uiminimap.cpp new file mode 100644 index 00000000..47ec8e41 --- /dev/null +++ b/src/client/uiminimap.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010-2013 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "uiminimap.h" +#include "minimap.h" +#include "game.h" + +#include + +UIMinimap::UIMinimap() +{ + m_crossEnabled = true; + m_zoom = 0; + m_minZoom = -5; + m_maxZoom = 5; +} + +void UIMinimap::drawSelf(Fw::DrawPane drawPane) +{ + UIWidget::drawSelf(drawPane); + + if((drawPane & Fw::ForegroundPane) == 0) + return; + + g_minimap.draw(getPaddingRect(), getCameraPosition(), m_scale); + + // draw a cross in the center + Rect vRect(0, 0, 2, 10); + Rect hRect(0, 0, 10, 2); + vRect.moveCenter(m_rect.center()); + hRect.moveCenter(m_rect.center()); + g_painter->setColor(Color::white); + g_painter->drawFilledRect(vRect); + g_painter->drawFilledRect(hRect); +} + +bool UIMinimap::setZoom(int zoom) +{ + if(zoom < m_minZoom || zoom > m_maxZoom) + return false; + m_zoom = zoom; + if(m_zoom < 0) + m_scale = 1.0f / (1 << std::abs(zoom)); + else if(m_zoom > 0) + m_scale = 1.0f * (1 << std::abs(zoom)); + else + m_scale = 1; + return true; +} + +void UIMinimap::followCreature(const CreaturePtr& creature) +{ + m_followingCreature = creature; + m_cameraPosition = Position(); +} + +void UIMinimap::setCameraPosition(const Position& pos) +{ + m_followingCreature = nullptr; + m_cameraPosition = pos; +} + +Position UIMinimap::getPosition(const Point& mousePos) +{ + return g_minimap.getPosition(mousePos, getPaddingRect(), getCameraPosition(), m_scale); +} + +Position UIMinimap::getCameraPosition() +{ + if(m_followingCreature) + return m_followingCreature->getPosition(); + else + return m_cameraPosition; +} + +void UIMinimap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) +{ + UIWidget::onStyleApply(styleName, styleNode); + for(const OTMLNodePtr& node : styleNode->children()) { + if(node->tag() == "zoom") + setZoom(node->value()); + else if(node->tag() == "max-zoom") + setMaxZoom(node->value()); + else if(node->tag() == "min-zoom") + setMinZoom(node->value()); + else if(node->tag() == "cross") + setCross(node->value()); + } +} diff --git a/src/client/uiminimap.h b/src/client/uiminimap.h new file mode 100644 index 00000000..91cb4c9a --- /dev/null +++ b/src/client/uiminimap.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010-2013 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef UIMINIMAP_H +#define UIMINIMAP_H + +#include "declarations.h" +#include + +class UIMinimap : public UIWidget +{ +public: + UIMinimap(); + + void drawSelf(Fw::DrawPane drawPane); + + bool zoomIn() { return setZoom(m_zoom-1); } + bool zoomOut() { return setZoom(m_zoom+1); } + + bool setZoom(int zoom); + void setMinZoom(int minZoom) { m_minZoom = minZoom; } + void setMaxZoom(int maxZoom) { m_maxZoom = maxZoom; } + void setCameraPosition(const Position& pos); + void setCross(bool enable) { m_crossEnabled = enable; } + void followCreature(const CreaturePtr& creature); + + Position getPosition(const Point& mousePos); + Position getCameraPosition(); + CreaturePtr getFollowingCreature() { return m_followingCreature; } + int getMinZoom() { return m_minZoom; } + int getMaxZoom() { return m_maxZoom; } + int getZoom() { return m_zoom; } + bool getCross() { return m_crossEnabled; } + float getScale() { return m_scale; } + +protected: + virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode); + +private: + Rect m_mapArea; + bool m_crossEnabled; + CreaturePtr m_followingCreature; + Position m_cameraPosition; + float m_scale; + int m_zoom; + int m_minZoom; + int m_maxZoom; +}; + +#endif diff --git a/src/framework/graphics/image.h b/src/framework/graphics/image.h index 318957c8..ba6510fa 100644 --- a/src/framework/graphics/image.h +++ b/src/framework/graphics/image.h @@ -37,9 +37,11 @@ public: void overwriteMask(const Color& maskedColor, const Color& insideColor = Color::white, const Color& outsideColor = Color::alpha); void blit(const Point& dest, const ImagePtr& other); void paste(const ImagePtr& other); + void resize(const Size& size) { m_size = size; m_pixels.resize(size.area() * m_bpp, 0); } bool nextMipmap(); void setPixel(int x, int y, uint8 *pixel) { memcpy(&m_pixels[(y * m_size.width() + x) * m_bpp], pixel, m_bpp);} + void setPixel(int x, int y, const Color& color) { uint32 tmp = color.rgba(); setPixel(x,y,(uint8*)&tmp); } std::vector& getPixels() { return m_pixels; } uint8* getPixelData() { return &m_pixels[0]; } diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index 15eb3077..f6aefb18 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -55,6 +55,21 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps, bool compress) createTexture(); + uploadPixels(image, buildMipmaps, compress); +} + +Texture::~Texture() +{ +#ifndef NDEBUG + assert(!g_app.isTerminated()); +#endif + // free texture from gl memory + if(g_graphics.ok() && m_id != 0) + glDeleteTextures(1, &m_id); +} + +void Texture::uploadPixels(const ImagePtr& image, bool buildMipmaps, bool compress) +{ ImagePtr glImage = image; if(m_size != m_glSize) { glImage = ImagePtr(new Image(m_glSize, image->getBpp())); @@ -77,16 +92,6 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps, bool compress) setupFilters(); } -Texture::~Texture() -{ -#ifndef NDEBUG - assert(!g_app.isTerminated()); -#endif - // free texture from gl memory - if(g_graphics.ok() && m_id != 0) - glDeleteTextures(1, &m_id); -} - void Texture::bind() { // must reset painter texture state diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index 8225d5b8..491092cf 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -33,6 +33,7 @@ public: Texture(const ImagePtr& image, bool buildMipmaps = false, bool compress = false); virtual ~Texture(); + void uploadPixels(const ImagePtr& image, bool buildMipmaps = false, bool compress = false); void bind(); void copyFromScreen(const Rect& screenRect); virtual bool buildHardwareMipmaps(); diff --git a/src/framework/util/size.h b/src/framework/util/size.h index d887a3a2..287ac73f 100644 --- a/src/framework/util/size.h +++ b/src/framework/util/size.h @@ -95,7 +95,7 @@ public: } } } - void scale(int w, int h, Fw::AspectRatioMode mode) { scale(TSize(w, h)); } + void scale(int w, int h, Fw::AspectRatioMode mode) { scale(TSize(w, h), mode); } float ratio() const { return (float)wd/ht; } T area() const { return wd*ht; }