Rework minimap rendering

This commit is contained in:
Eduardo Bart 2013-01-20 21:17:56 -02:00
parent 18a37393c5
commit ae731ddefc
23 changed files with 531 additions and 148 deletions

View File

@ -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

View File

@ -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')
@ -208,7 +203,7 @@ function getMapArea()
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

View File

@ -47,9 +47,10 @@ MiniWindow
size: 14 14
MiniWindowContents
UIMap
UIMinimap
id: minimap
anchors.fill: parent
cross: true
Panel
id: flagsPanel

View File

@ -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

View File

@ -28,6 +28,7 @@
#include "map.h"
#include "shadermanager.h"
#include "spritemanager.h"
#include "minimap.h"
#include <framework/core/configmanager.h>
Client g_client;
@ -38,6 +39,7 @@ void Client::init(std::vector<std::string>& 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();

View File

@ -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;
}

View File

@ -92,11 +92,13 @@ typedef stdext::shared_object_ptr<ProtocolLogin> ProtocolLoginPtr;
class UIItem;
class UICreature;
class UIMap;
class UIMinimap;
class UIProgressRect;
typedef stdext::shared_object_ptr<UIItem> UIItemPtr;
typedef stdext::shared_object_ptr<UICreature> UICreaturePtr;
typedef stdext::shared_object_ptr<UIMap> UIMapPtr;
typedef stdext::shared_object_ptr<UIMinimap> UIMinimapPtr;
typedef stdext::shared_object_ptr<UIProgressRect> UIProgressRectPtr;
#endif

View File

@ -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<UIMap>("setAutoViewMode", &UIMap::setAutoViewMode);
g_lua.bindClassMemberFunction<UIMap>("setDrawFlags", &UIMap::setDrawFlags);
g_lua.bindClassMemberFunction<UIMap>("setDrawTexts", &UIMap::setDrawTexts);
g_lua.bindClassMemberFunction<UIMap>("setDrawMinimapColors", &UIMap::setDrawMinimapColors);
g_lua.bindClassMemberFunction<UIMap>("setDrawLights", &UIMap::setDrawLights);
g_lua.bindClassMemberFunction<UIMap>("setAnimated", &UIMap::setAnimated);
g_lua.bindClassMemberFunction<UIMap>("setKeepAspectRatio", &UIMap::setKeepAspectRatio);
@ -557,7 +557,6 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIMap>("isMultifloor", &UIMap::isMultifloor);
g_lua.bindClassMemberFunction<UIMap>("isAutoViewModeEnabled", &UIMap::isAutoViewModeEnabled);
g_lua.bindClassMemberFunction<UIMap>("isDrawingTexts", &UIMap::isDrawingTexts);
g_lua.bindClassMemberFunction<UIMap>("isDrawingMinimapColors", &UIMap::isDrawingMinimapColors);
g_lua.bindClassMemberFunction<UIMap>("isDrawingLights", &UIMap::isDrawingLights);
g_lua.bindClassMemberFunction<UIMap>("isAnimating", &UIMap::isAnimating);
g_lua.bindClassMemberFunction<UIMap>("isKeepAspectRatioEnabled", &UIMap::isKeepAspectRatioEnabled);
@ -574,6 +573,25 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIMap>("getMapShader", &UIMap::getMapShader);
g_lua.bindClassMemberFunction<UIMap>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight);
g_lua.registerClass<UIMinimap, UIWidget>();
g_lua.bindClassStaticFunction<UIMinimap>("create", []{ return UIMinimapPtr(new UIMinimap); });
g_lua.bindClassMemberFunction<UIMinimap>("zoomIn", &UIMinimap::zoomIn);
g_lua.bindClassMemberFunction<UIMinimap>("zoomOut", &UIMinimap::zoomOut);
g_lua.bindClassMemberFunction<UIMinimap>("setZoom", &UIMinimap::setZoom);
g_lua.bindClassMemberFunction<UIMinimap>("setMixZoom", &UIMinimap::setMinZoom);
g_lua.bindClassMemberFunction<UIMinimap>("setMaxZoom", &UIMinimap::setMaxZoom);
g_lua.bindClassMemberFunction<UIMinimap>("setCameraPosition", &UIMinimap::setCameraPosition);
g_lua.bindClassMemberFunction<UIMinimap>("setCross", &UIMinimap::setCross);
g_lua.bindClassMemberFunction<UIMinimap>("followCreature", &UIMinimap::followCreature);
g_lua.bindClassMemberFunction<UIMinimap>("getPosition", &UIMinimap::getPosition);
g_lua.bindClassMemberFunction<UIMinimap>("getCameraPosition", &UIMinimap::getCameraPosition);
g_lua.bindClassMemberFunction<UIMinimap>("getFollowingCreature", &UIMinimap::getFollowingCreature);
g_lua.bindClassMemberFunction<UIMinimap>("getMinZoom", &UIMinimap::getMinZoom);
g_lua.bindClassMemberFunction<UIMinimap>("getMaxZoom", &UIMinimap::getMaxZoom);
g_lua.bindClassMemberFunction<UIMinimap>("getZoom", &UIMinimap::getZoom);
g_lua.bindClassMemberFunction<UIMinimap>("getCross", &UIMinimap::getCross);
g_lua.bindClassMemberFunction<UIMinimap>("getScale", &UIMinimap::getScale);
g_lua.registerClass<UIProgressRect, UIWidget>();
g_lua.bindClassStaticFunction<UIProgressRect>("create", []{ return UIProgressRectPtr(new UIProgressRect); } );
g_lua.bindClassMemberFunction<UIProgressRect>("setPercent", &UIProgressRect::setPercent);

View File

@ -28,6 +28,7 @@
#include "missile.h"
#include "statictext.h"
#include "mapview.h"
#include "minimap.h"
#include <framework/core/eventdispatcher.h>
#include <framework/core/application.h>
@ -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<Missile>();
@ -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();) {

View File

@ -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);

View File

@ -440,6 +440,8 @@ bool Map::loadOtcm(const std::string& fileName)
if(item->isValid())
tile->addThing(item, stackPos++);
}
g_map.notificateTileUpdate(pos);
}
fin->close();

View File

@ -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));
}
}
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,7 +414,6 @@ 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;
@ -469,10 +429,6 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized
g_logger.traceError("reached max zoom out");
return;
}
} else {
tileSize = 1;
bufferSize = visibleDimension + Size(3,3);
}
Size drawDimension = visibleDimension + Size(3,3);
Point virtualCenterOffset = (drawDimension/2 - Size(1,1)).toPoint();
@ -518,7 +474,6 @@ void MapView::updateGeometry(const Size& visibleDimension, const Size& optimized
void MapView::onTileUpdate(const Position& pos)
{
if(!m_drawMinimapColors)
requestVisibleTilesCacheUpdate();
}
@ -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))

View File

@ -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<true> m_autoViewMode;
stdext::boolean<true> m_drawTexts;
stdext::boolean<true> m_smooth;
stdext::boolean<false> m_drawMinimapColors;
stdext::boolean<false> m_drawLights;
stdext::boolean<true> m_follow;
std::vector<TilePtr> m_cachedVisibleTiles;

View File

@ -22,4 +22,200 @@
#include "minimap.h"
#include "tile.h"
#include <framework/graphics/image.h>
#include <framework/graphics/texture.h>
#include <framework/graphics/painter.h>
#include <framework/graphics/framebuffermanager.h>
#include <boost/concept_check.hpp>
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;x<MMBLOCK_SIZE;++x)
for(int y=0;y<MMBLOCK_SIZE;++y)
m_image->setPixel(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)
{
}

View File

@ -24,19 +24,51 @@
#ifndef MINIMAP_H
#define MINIMAP_H
#include "global.h"
#include <framework/graphics/image.h>
/*
#include "declarations.h"
#include <framework/graphics/declarations.h>
enum {
MINIMAP_AREA_SIZE = 32
MMBLOCK_SIZE = 64
};
struct MinimapArea
enum MinimapTileFlags {
MinimapTilePathable = 1,
MinimapTileWalkable = 2,
MinimapTileChangesFloor = 4
};
#pragma pack(push,1) // disable memory alignment
struct MinimapTile
{
ImagePtr img;
TexturePtr tex;
uint8 colors[MINIMAP_AREA_SIZE][MINIMAP_AREA_SIZE];
stdext::boolean<true> 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<MinimapTile, MMBLOCK_SIZE *MMBLOCK_SIZE> getTiles() { return m_tiles; }
bool shouldDraw() { return m_shouldDraw; }
private:
ImagePtr m_image;
TexturePtr m_texture;
stdext::boolean<false> m_shouldDraw;
std::array<MinimapTile, MMBLOCK_SIZE *MMBLOCK_SIZE> m_tiles;
stdext::boolean<true> 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);
void updateTile(const Position& pos, const TilePtr& tile);
bool checkTileProperty(const Position& pos, int flags);
void loadOtmm(const std::string& fileName);
void saveOtmm(const std::string& fileName);
private:
struct MinimaAreaHasher : std::unary_function<Position, std::size_t> {
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<Position, ImagePtr, MinimaAreaHasher> m_areas;
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<uint, MinimapBlock> m_tileBlocks[Otc::MAX_Z+1];
};
extern Minimap g_minimap;
*/
#endif

View File

@ -179,8 +179,6 @@ void UIMap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleN
setAutoViewMode(node->value<bool>());
else if(node->tag() == "draw-texts")
setDrawTexts(node->value<bool>());
else if(node->tag() == "draw-minimap-colors")
setDrawMinimapColors(node->value<bool>());
else if(node->tag() == "draw-lights")
setDrawLights(node->value<bool>());
else if(node->tag() == "animated")

View File

@ -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; }

108
src/client/uiminimap.cpp Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/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 <framework/graphics/painter.h>
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<int>());
else if(node->tag() == "max-zoom")
setMaxZoom(node->value<int>());
else if(node->tag() == "min-zoom")
setMinZoom(node->value<int>());
else if(node->tag() == "cross")
setCross(node->value<bool>());
}
}

69
src/client/uiminimap.h Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/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 <framework/ui/uiwidget.h>
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

View File

@ -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<uint8>& getPixels() { return m_pixels; }
uint8* getPixelData() { return &m_pixels[0]; }

View File

@ -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

View File

@ -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();

View File

@ -95,7 +95,7 @@ public:
}
}
}
void scale(int w, int h, Fw::AspectRatioMode mode) { scale(TSize<T>(w, h)); }
void scale(int w, int h, Fw::AspectRatioMode mode) { scale(TSize<T>(w, h), mode); }
float ratio() const { return (float)wd/ht; }
T area() const { return wd*ht; }