diff --git a/client/adventureMap/MapRenderer.h b/client/adventureMap/MapRenderer.h index 40f640b8b..e3ffc7153 100644 --- a/client/adventureMap/MapRenderer.h +++ b/client/adventureMap/MapRenderer.h @@ -136,6 +136,15 @@ public: void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates); }; +class MapRendererOverlay +{ + std::unique_ptr iconsStorage; +public: + MapRendererOverlay(); + + void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates); +}; + class MapRenderer { MapRendererTerrain rendererTerrain; diff --git a/client/adventureMap/MapRendererContext.h b/client/adventureMap/MapRendererContext.h index ae1920877..4776d9b65 100644 --- a/client/adventureMap/MapRendererContext.h +++ b/client/adventureMap/MapRendererContext.h @@ -67,6 +67,9 @@ public: // /// returns size of ouput tile, in pixels. 32x32 for "standard" map, may be smaller for world view mode // virtual Point getTileSize() const = 0; + /// if true, world view overlay will be shown + virtual bool showOverlay() const = 0; + /// if true, map grid should be visible on map virtual bool showGrid() const = 0; virtual bool showVisitable() const = 0; diff --git a/client/adventureMap/MapView.cpp b/client/adventureMap/MapView.cpp index 94ee85ec8..a62787a82 100644 --- a/client/adventureMap/MapView.cpp +++ b/client/adventureMap/MapView.cpp @@ -20,6 +20,7 @@ #include "../gui/CGuiHandler.h" #include "../render/CAnimation.h" #include "../render/Canvas.h" +#include "../render/IImage.h" #include "../renderSDL/SDL_Extensions.h" #include "../../CCallback.h" @@ -33,9 +34,14 @@ MapViewCache::~MapViewCache() = default; MapViewCache::MapViewCache(const std::shared_ptr & model) : model(model) , mapRenderer(new MapRenderer()) + , iconsStorage(new CAnimation("VwSymbol")) , intermediate(new Canvas(Point(32,32))) , terrain(new Canvas(model->getCacheDimensionsPixels())) { + iconsStorage->preload(); + for (size_t i = 0; i < iconsStorage->size(); ++i) + iconsStorage->getImage(i)->setBlitMode(EImageBlitMode::COLORKEY); + } Canvas MapViewCache::getTile(const int3 & coordinates) @@ -43,6 +49,45 @@ Canvas MapViewCache::getTile(const int3 & coordinates) return Canvas(*terrain, model->getCacheTileArea(coordinates)); } +std::shared_ptr MapViewCache::getOverlayImageForTile(const std::shared_ptr & context, const int3 & coordinates) +{ + if (!context->isVisible(coordinates)) + return nullptr; + + for(const auto & objectID : context->getObjects(coordinates)) + { + const auto * object = context->getObject(objectID); + + if (!object->visitableAt(coordinates.x, coordinates.y)) + continue; + + size_t ownerIndex = PlayerColor::PLAYER_LIMIT.getNum() * static_cast(EWorldViewIcon::ICONS_PER_PLAYER); + if (object->tempOwner.isValidPlayer()) + ownerIndex = object->tempOwner.getNum() * static_cast(EWorldViewIcon::ICONS_PER_PLAYER); + + switch (object->ID) + { + case Obj::MONOLITH_ONE_WAY_ENTRANCE: + case Obj::MONOLITH_ONE_WAY_EXIT: + case Obj::MONOLITH_TWO_WAY: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::TELEPORT)); + case Obj::SUBTERRANEAN_GATE: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::GATE)); + case Obj::ARTIFACT: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::ARTIFACT)); + case Obj::TOWN: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::TOWN)); + case Obj::HERO: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::HERO)); + case Obj::MINE: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::MINE_WOOD) + object->subID); + case Obj::RESOURCE: + return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::RES_WOOD) + object->subID); + } + } + return nullptr; +} + void MapViewCache::updateTile(const std::shared_ptr & context, const int3 & coordinates) { Canvas target = getTile(coordinates); @@ -67,7 +112,7 @@ void MapViewCache::update(const std::shared_ptr & context) updateTile(context, {x, y, model->getLevel()}); } -void MapViewCache::render(Canvas & target) +void MapViewCache::render(const std::shared_ptr & context, Canvas & target) { Rect dimensions = model->getTilesTotalRect(); @@ -79,6 +124,17 @@ void MapViewCache::render(Canvas & target) Canvas source = getTile(tile); Rect targetRect = model->getTargetTileArea(tile); target.draw(source, targetRect.topLeft()); + + if (context->showOverlay()) + { + auto overlay = getOverlayImageForTile(context, tile); + + if (overlay) + { + Point position = targetRect.center() - overlay->dimensions() / 2; + target.draw(overlay, position); + } + } } } } @@ -115,7 +171,7 @@ void MapView::show(SDL_Surface * to) controller->update(GH.mainFPSmng->getElapsedMilliseconds()); tilesCache->update(context); - tilesCache->render(targetClipped); + tilesCache->render(context, targetClipped); } void MapView::showAll(SDL_Surface * to) @@ -194,6 +250,11 @@ size_t MapRendererContext::terrainImageIndex(size_t groupSize) const // return Point(32, 32); //} +bool MapRendererContext::showOverlay() const +{ + return worldViewModeActive; +} + bool MapRendererContext::showGrid() const { return settings["gameTweaks"]["showGrid"].Bool(); @@ -550,7 +611,8 @@ void MapViewController::update(uint32_t timeDelta) } context->animationTime += timeDelta; - context->tileSize = Point(32,32); //model->getSingleTileSize(); + //context->tileSize = Point(32,32); //model->getSingleTileSize(); + context->worldViewModeActive = model->getSingleTileSize() != Point(32,32); } void MapViewController::onObjectFadeIn(const CGObjectInstance * obj) diff --git a/client/adventureMap/MapView.h b/client/adventureMap/MapView.h index c3071250c..267678975 100644 --- a/client/adventureMap/MapView.h +++ b/client/adventureMap/MapView.h @@ -38,7 +38,7 @@ class MapRendererContext : public IMapRendererContext boost::multi_array objects; - Point tileSize = Point(32, 32); + //Point tileSize = Point(32, 32); uint32_t animationTime = 0; boost::optional movementAnimation; @@ -47,6 +47,8 @@ class MapRendererContext : public IMapRendererContext boost::optional fadeOutAnimation; boost::optional fadeInAnimation; + bool worldViewModeActive = false; + public: MapRendererContext(); @@ -69,6 +71,8 @@ public: size_t objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const override; size_t terrainImageIndex(size_t groupSize) const override; // Point getTileSize() const override; + + bool showOverlay() const override; bool showGrid() const override; bool showVisitable() const override; bool showBlockable() const override; @@ -130,10 +134,12 @@ class MapViewCache std::unique_ptr intermediate; std::unique_ptr mapRenderer; + std::unique_ptr iconsStorage; Canvas getTile(const int3 & coordinates); void updateTile(const std::shared_ptr & context, const int3 & coordinates); + std::shared_ptr getOverlayImageForTile(const std::shared_ptr & context, const int3 & coordinates); public: explicit MapViewCache(const std::shared_ptr & model); ~MapViewCache(); @@ -142,7 +148,7 @@ public: void update(const std::shared_ptr & context); /// renders updated terrain cache onto provided canvas - void render(Canvas & target); + void render(const std::shared_ptr &context, Canvas & target); }; /// Class responsible for updating view state, diff --git a/client/adventureMap/mapHandler.cpp b/client/adventureMap/mapHandler.cpp index 8b4cd3460..dcd6cbbb3 100644 --- a/client/adventureMap/mapHandler.cpp +++ b/client/adventureMap/mapHandler.cpp @@ -22,108 +22,6 @@ #include "../../lib/CGeneralTextHandler.h" #include "../../lib/TerrainHandler.h" -/* -std::shared_ptr CMapWorldViewBlitter::objectToIcon(Obj id, si32 subId, PlayerColor owner) const -{ - int ownerIndex = 0; - if(owner < PlayerColor::PLAYER_LIMIT) - { - ownerIndex = owner.getNum() * 19; - } - else if (owner == PlayerColor::NEUTRAL) - { - ownerIndex = PlayerColor::PLAYER_LIMIT.getNum() * 19; - } - - switch(id) - { - case Obj::MONOLITH_ONE_WAY_ENTRANCE: - case Obj::MONOLITH_ONE_WAY_EXIT: - case Obj::MONOLITH_TWO_WAY: - return info->icons->getImage((int)EWorldViewIcon::TELEPORT); - case Obj::SUBTERRANEAN_GATE: - return info->icons->getImage((int)EWorldViewIcon::GATE); - case Obj::ARTIFACT: - return info->icons->getImage((int)EWorldViewIcon::ARTIFACT); - case Obj::TOWN: - return info->icons->getImage((int)EWorldViewIcon::TOWN + ownerIndex); - case Obj::HERO: - return info->icons->getImage((int)EWorldViewIcon::HERO + ownerIndex); - case Obj::MINE: - return info->icons->getImage((int)EWorldViewIcon::MINE_WOOD + subId + ownerIndex); - case Obj::RESOURCE: - return info->icons->getImage((int)EWorldViewIcon::RES_WOOD + subId + ownerIndex); - } - return std::shared_ptr(); -} -*/ - -/* -void CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const -{ - auto drawIcon = [this,targetSurf](Obj id, si32 subId, PlayerColor owner) - { - auto wvIcon = this->objectToIcon(id, subId, owner); - - if(nullptr != wvIcon) - { - // centering icon on the object - Point dest(realPos.x + tileSize / 2 - wvIcon->width() / 2, realPos.y + tileSize / 2 - wvIcon->height() / 2); - wvIcon->draw(targetSurf, dest.x, dest.y); - } - }; - - auto & objects = tile.objects; - for(auto & object : objects) - { - const CGObjectInstance * obj = object.obj; - if(!obj) - continue; - - const bool sameLevel = obj->pos.z == pos.z; - - //FIXME: Don't read options in a loop :v - const bool isVisible = settings["session"]["spectate"].Bool() ? true : (*info->visibilityMap)[pos.z][pos.x][pos.y]; - const bool isVisitable = obj->visitableAt(pos.x, pos.y); - - if(sameLevel && isVisible && isVisitable) - drawIcon(obj->ID, obj->subID, obj->tempOwner); - } -} -*/ -/* -void CMapWorldViewBlitter::drawOverlayEx(SDL_Surface * targetSurf) -{ - if(nullptr == info->additionalIcons) - return; - - const int3 bottomRight = pos + tileCount; - - for(const ObjectPosInfo & iconInfo : *(info->additionalIcons)) - { - if( iconInfo.pos.z != pos.z) - continue; - - if((iconInfo.pos.x < topTile.x) || (iconInfo.pos.y < topTile.y)) - continue; - - if((iconInfo.pos.x > bottomRight.x) || (iconInfo.pos.y > bottomRight.y)) - continue; - - realPos.x = initPos.x + (iconInfo.pos.x - topTile.x) * tileSize; - realPos.y = initPos.y + (iconInfo.pos.y - topTile.y) * tileSize; - - auto wvIcon = this->objectToIcon(iconInfo.id, iconInfo.subId, iconInfo.owner); - - if(nullptr != wvIcon) - { - // centering icon on the object - Point dest(realPos.x + tileSize / 2 - wvIcon->width() / 2, realPos.y + tileSize / 2 - wvIcon->height() / 2); - wvIcon->draw(targetSurf, dest.x, dest.y); - } - } -} -*/ /* void CMapPuzzleViewBlitter::drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const {