mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Partial support for caching to detect updated tiles
This commit is contained in:
parent
cd5f0bb36f
commit
4fdf3d4a87
@ -34,6 +34,9 @@ public:
|
||||
/// returns true if chosen coordinates exist on map
|
||||
virtual bool isInMap(const int3 & coordinates) const = 0;
|
||||
|
||||
// /// returns true if selected tile has animation and should not be cached
|
||||
// virtual bool tileAnimated(const int3 & coordinates) const = 0;
|
||||
|
||||
/// returns tile by selected coordinates. Coordinates MUST be valid
|
||||
virtual const TerrainTile & getMapTile(const int3 & coordinates) const = 0;
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "MapRenderer.h"
|
||||
|
||||
#include "MapRendererContext.h"
|
||||
#include "IMapRendererContext.h"
|
||||
#include "mapHandler.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
@ -92,7 +92,7 @@ MapTileStorage::MapTileStorage(size_t capacity)
|
||||
{
|
||||
}
|
||||
|
||||
void MapTileStorage::load(size_t index, const std::string & filename)
|
||||
void MapTileStorage::load(size_t index, const std::string & filename, EImageBlitMode blitMode)
|
||||
{
|
||||
auto & terrainAnimations = animations[index];
|
||||
|
||||
@ -100,6 +100,9 @@ void MapTileStorage::load(size_t index, const std::string & filename)
|
||||
{
|
||||
entry = std::make_unique<CAnimation>(filename);
|
||||
entry->preload();
|
||||
|
||||
for(size_t i = 0; i < entry->size(); ++i)
|
||||
entry->getImage(i)->setBlitMode(blitMode);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < terrainAnimations[0]->size(); ++i)
|
||||
@ -122,7 +125,7 @@ MapRendererTerrain::MapRendererTerrain()
|
||||
: storage(VLC->terrainTypeHandler->objects.size())
|
||||
{
|
||||
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
||||
storage.load(terrain->getIndex(), terrain->tilesFilename);
|
||||
storage.load(terrain->getIndex(), terrain->tilesFilename, EImageBlitMode::OPAQUE);
|
||||
}
|
||||
|
||||
void MapRendererTerrain::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
|
||||
@ -146,15 +149,23 @@ void MapRendererTerrain::renderTile(const IMapRendererContext & context, Canvas
|
||||
image->shiftPalette(242, 14, context.terrainImageIndex(14));
|
||||
}
|
||||
|
||||
image->setBlitMode(EImageBlitMode::OPAQUE);
|
||||
target.draw(image, Point(0, 0));
|
||||
}
|
||||
|
||||
uint8_t MapRendererTerrain::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
const TerrainTile & mapTile = context.getMapTile(coordinates);
|
||||
|
||||
if(mapTile.terType->getId() == ETerrainId::LAVA || mapTile.terType->getId() == ETerrainId::WATER)
|
||||
return context.terrainImageIndex(250);
|
||||
return 0xff-1;
|
||||
}
|
||||
|
||||
MapRendererRiver::MapRendererRiver()
|
||||
: storage(VLC->riverTypeHandler->objects.size())
|
||||
{
|
||||
for(const auto & river : VLC->riverTypeHandler->objects)
|
||||
storage.load(river->getIndex(), river->tilesFilename);
|
||||
storage.load(river->getIndex(), river->tilesFilename, EImageBlitMode::COLORKEY);
|
||||
}
|
||||
|
||||
void MapRendererRiver::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
|
||||
@ -191,11 +202,22 @@ void MapRendererRiver::renderTile(const IMapRendererContext & context, Canvas &
|
||||
target.draw(image, Point(0, 0));
|
||||
}
|
||||
|
||||
uint8_t MapRendererRiver::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
const TerrainTile & mapTile = context.getMapTile(coordinates);
|
||||
|
||||
if(mapTile.riverType->getId() == River::WATER_RIVER ||
|
||||
mapTile.riverType->getId() == River::MUD_RIVER ||
|
||||
mapTile.riverType->getId() == River::LAVA_RIVER)
|
||||
return context.terrainImageIndex(250);
|
||||
return 0xff-1;
|
||||
}
|
||||
|
||||
MapRendererRoad::MapRendererRoad()
|
||||
: storage(VLC->roadTypeHandler->objects.size())
|
||||
{
|
||||
for(const auto & road : VLC->roadTypeHandler->objects)
|
||||
storage.load(road->getIndex(), road->tilesFilename);
|
||||
storage.load(road->getIndex(), road->tilesFilename, EImageBlitMode::COLORKEY);
|
||||
}
|
||||
|
||||
void MapRendererRoad::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
|
||||
@ -228,6 +250,11 @@ void MapRendererRoad::renderTile(const IMapRendererContext & context, Canvas & t
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MapRendererRoad::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MapRendererBorder::MapRendererBorder()
|
||||
{
|
||||
animation = std::make_unique<CAnimation>("EDG");
|
||||
@ -278,6 +305,11 @@ void MapRendererBorder::renderTile(const IMapRendererContext & context, Canvas &
|
||||
target.draw(image, Point(0, 0));
|
||||
}
|
||||
|
||||
uint8_t MapRendererBorder::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MapRendererFow::MapRendererFow()
|
||||
{
|
||||
fogOfWarFullHide = std::make_unique<CAnimation>("TSHRC");
|
||||
@ -285,6 +317,9 @@ MapRendererFow::MapRendererFow()
|
||||
fogOfWarPartialHide = std::make_unique<CAnimation>("TSHRE");
|
||||
fogOfWarPartialHide->preload();
|
||||
|
||||
for(size_t i = 0; i < fogOfWarFullHide->size(); ++i)
|
||||
fogOfWarFullHide->getImage(i)->setBlitMode(EImageBlitMode::OPAQUE);
|
||||
|
||||
static const std::vector<int> rotations = {22, 15, 2, 13, 12, 16, 28, 17, 20, 19, 7, 24, 26, 25, 30, 32, 27};
|
||||
|
||||
size_t size = fogOfWarPartialHide->size(0); //group size after next rotation
|
||||
@ -321,6 +356,15 @@ void MapRendererFow::renderTile(const IMapRendererContext & context, Canvas & ta
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MapRendererFow::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
const NeighborTilesInfo neighborInfo(context, coordinates);
|
||||
int retBitmapID = neighborInfo.getBitmapID();
|
||||
if(retBitmapID < 0)
|
||||
return 0xff-1;
|
||||
return retBitmapID;
|
||||
}
|
||||
|
||||
std::shared_ptr<CAnimation> MapRendererObjects::getBaseAnimation(const CGObjectInstance* obj)
|
||||
{
|
||||
const auto & info = obj->appearance;
|
||||
@ -485,6 +529,36 @@ void MapRendererObjects::renderTile(const IMapRendererContext & context, Canvas
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MapRendererObjects::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
for(const auto & objectID : context.getObjects(coordinates))
|
||||
{
|
||||
const auto * objectInstance = context.getObject(objectID);
|
||||
size_t groupIndex = context.objectGroupIndex(objectInstance->id);
|
||||
Point offsetPixels = context.objectImageOffset(objectInstance->id, coordinates);
|
||||
|
||||
auto base = getBaseAnimation(objectInstance);
|
||||
auto flag = getFlagAnimation(objectInstance);
|
||||
|
||||
if (base && base->size(groupIndex) > 1)
|
||||
{
|
||||
auto imageIndex = context.objectImageIndex(objectID, base->size(groupIndex));
|
||||
auto image = base->getImage(imageIndex, groupIndex);
|
||||
if ( offsetPixels.x < image->dimensions().x && offsetPixels.y < image->dimensions().y)
|
||||
return context.objectImageIndex(objectID, 250);
|
||||
}
|
||||
|
||||
if (flag && flag->size(groupIndex) > 1)
|
||||
{
|
||||
auto imageIndex = context.objectImageIndex(objectID, flag->size(groupIndex));
|
||||
auto image = flag->getImage(imageIndex, groupIndex);
|
||||
if ( offsetPixels.x < image->dimensions().x && offsetPixels.y < image->dimensions().y)
|
||||
return context.objectImageIndex(objectID, 250);
|
||||
}
|
||||
}
|
||||
return 0xff-1;
|
||||
}
|
||||
|
||||
MapRendererDebug::MapRendererDebug()
|
||||
: imageGrid(IImage::createFromFile("debug/grid", EImageBlitMode::ALPHA))
|
||||
, imageBlockable(IImage::createFromFile("debug/blocked", EImageBlitMode::ALPHA))
|
||||
@ -521,28 +595,33 @@ void MapRendererDebug::renderTile(const IMapRendererContext & context, Canvas &
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MapRendererDebug::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MapRendererPath::MapRendererPath()
|
||||
: pathNodes(new CAnimation("ADAG"))
|
||||
{
|
||||
pathNodes->preload();
|
||||
}
|
||||
|
||||
void MapRendererPath::renderImage(Canvas & target, bool reachableToday, size_t imageIndex)
|
||||
size_t MapRendererPath::selectImageReachability(bool reachableToday, size_t imageIndex)
|
||||
{
|
||||
const static size_t unreachableTodayOffset = 25;
|
||||
|
||||
if(reachableToday)
|
||||
target.draw(pathNodes->getImage(imageIndex), Point(0, 0));
|
||||
else
|
||||
target.draw(pathNodes->getImage(imageIndex + unreachableTodayOffset), Point(0, 0));
|
||||
if(!reachableToday)
|
||||
return unreachableTodayOffset + imageIndex;
|
||||
|
||||
return imageIndex;
|
||||
}
|
||||
|
||||
void MapRendererPath::renderImageCross(Canvas & target, bool reachableToday, const int3 & curr)
|
||||
size_t MapRendererPath::selectImageCross(bool reachableToday, const int3 & curr)
|
||||
{
|
||||
renderImage(target, reachableToday, 0);
|
||||
return selectImageReachability(reachableToday, 0);
|
||||
}
|
||||
|
||||
void MapRendererPath::renderImageArrow(Canvas & target, bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next)
|
||||
size_t MapRendererPath::selectImageArrow(bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next)
|
||||
{
|
||||
// Vector directions
|
||||
// 0 1 2
|
||||
@ -571,10 +650,18 @@ void MapRendererPath::renderImageArrow(Canvas & target, bool reachableToday, con
|
||||
size_t leaveDirection = (prev.x - curr.x + 1) + 3 * (prev.y - curr.y + 1);
|
||||
size_t imageIndex = directionToArrowIndex[enterDirection][leaveDirection];
|
||||
|
||||
renderImage(target, reachableToday, imageIndex);
|
||||
return selectImageReachability(reachableToday, imageIndex);
|
||||
}
|
||||
|
||||
void MapRendererPath::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
|
||||
{
|
||||
size_t imageID = selectImage(context, coordinates);
|
||||
|
||||
if (imageID < pathNodes->size())
|
||||
target.draw(pathNodes->getImage(imageID), Point(0,0));
|
||||
}
|
||||
|
||||
size_t MapRendererPath::selectImage(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
const auto & functor = [&](const CGPathNode & node)
|
||||
{
|
||||
@ -583,31 +670,70 @@ void MapRendererPath::renderTile(const IMapRendererContext & context, Canvas & t
|
||||
|
||||
const auto * path = context.currentPath();
|
||||
if(!path)
|
||||
return;
|
||||
return std::numeric_limits<size_t>::max();
|
||||
|
||||
const auto & iter = boost::range::find_if(path->nodes, functor);
|
||||
|
||||
if(iter == path->nodes.end())
|
||||
return;
|
||||
return std::numeric_limits<size_t>::max();
|
||||
|
||||
bool reachableToday = iter->turns == 0;
|
||||
if(iter == path->nodes.begin())
|
||||
renderImageCross(target, reachableToday, iter->coord);
|
||||
return selectImageCross(reachableToday, iter->coord);
|
||||
|
||||
auto next = iter + 1;
|
||||
auto prev = iter - 1;
|
||||
|
||||
// start of path - current hero location
|
||||
if(next == path->nodes.end())
|
||||
return;
|
||||
return std::numeric_limits<size_t>::max();
|
||||
|
||||
bool pathContinuous = iter->coord.areNeighbours(next->coord) && iter->coord.areNeighbours(prev->coord);
|
||||
bool embarking = iter->action == CGPathNode::EMBARK || iter->action == CGPathNode::DISEMBARK;
|
||||
|
||||
if(pathContinuous && !embarking)
|
||||
renderImageArrow(target, reachableToday, iter->coord, prev->coord, next->coord);
|
||||
return selectImageArrow(reachableToday, iter->coord, prev->coord, next->coord);
|
||||
|
||||
return selectImageCross(reachableToday, iter->coord);
|
||||
}
|
||||
|
||||
uint8_t MapRendererPath::checksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
return selectImage(context, coordinates) & 0xff;
|
||||
}
|
||||
|
||||
MapRenderer::TileChecksum MapRenderer::getTileChecksum(const IMapRendererContext & context, const int3 & coordinates)
|
||||
{
|
||||
// computes basic checksum to determine whether tile needs an update
|
||||
// if any component gives different value, tile will be updated
|
||||
TileChecksum result;
|
||||
boost::range::fill(result, std::numeric_limits<uint8_t>::max());
|
||||
|
||||
if(!context.isInMap(coordinates))
|
||||
{
|
||||
result[0] = rendererBorder.checksum(context, coordinates);
|
||||
return result;
|
||||
}
|
||||
|
||||
const NeighborTilesInfo neighborInfo(context, coordinates);
|
||||
|
||||
if(!context.isVisible(coordinates) && neighborInfo.areAllHidden())
|
||||
{
|
||||
result[7] = rendererFow.checksum(context, coordinates);
|
||||
}
|
||||
else
|
||||
renderImageCross(target, reachableToday, iter->coord);
|
||||
{
|
||||
result[1] = rendererTerrain.checksum(context, coordinates);
|
||||
result[2] = rendererRiver.checksum(context, coordinates);
|
||||
result[3] = rendererRoad.checksum(context, coordinates);
|
||||
result[4] = rendererObjects.checksum(context, coordinates);
|
||||
result[5] = rendererPath.checksum(context, coordinates);
|
||||
result[6] = rendererDebug.checksum(context, coordinates);
|
||||
|
||||
if(!context.isVisible(coordinates))
|
||||
result[7] = rendererFow.checksum(context, coordinates);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MapRenderer::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
|
||||
@ -636,5 +762,4 @@ void MapRenderer::renderTile(const IMapRendererContext & context, Canvas & targe
|
||||
if(!context.isVisible(coordinates))
|
||||
rendererFow.renderTile(context, target, coordinates);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,8 +9,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "MapRendererContext.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class int3;
|
||||
@ -22,6 +20,8 @@ VCMI_LIB_NAMESPACE_END
|
||||
class CAnimation;
|
||||
class IImage;
|
||||
class Canvas;
|
||||
class IMapRendererContext;
|
||||
enum class EImageBlitMode : uint8_t;
|
||||
|
||||
class MapTileStorage
|
||||
{
|
||||
@ -30,7 +30,7 @@ class MapTileStorage
|
||||
|
||||
public:
|
||||
explicit MapTileStorage(size_t capacity);
|
||||
void load(size_t index, const std::string & filename);
|
||||
void load(size_t index, const std::string & filename, EImageBlitMode blitMode);
|
||||
std::shared_ptr<IImage> find(size_t fileIndex, size_t rotationIndex, size_t imageIndex);
|
||||
};
|
||||
|
||||
@ -40,6 +40,8 @@ class MapRendererTerrain
|
||||
|
||||
public:
|
||||
MapRendererTerrain();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -49,6 +51,8 @@ class MapRendererRiver
|
||||
|
||||
public:
|
||||
MapRendererRiver();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -58,6 +62,8 @@ class MapRendererRoad
|
||||
|
||||
public:
|
||||
MapRendererRoad();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -77,6 +83,7 @@ class MapRendererObjects
|
||||
void renderObject(const IMapRendererContext & context, Canvas & target, const int3 & coordinates, const CGObjectInstance * obj);
|
||||
|
||||
public:
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -88,6 +95,8 @@ class MapRendererBorder
|
||||
|
||||
public:
|
||||
MapRendererBorder();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -98,6 +107,8 @@ class MapRendererFow
|
||||
|
||||
public:
|
||||
MapRendererFow();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -105,12 +116,15 @@ class MapRendererPath
|
||||
{
|
||||
std::unique_ptr<CAnimation> pathNodes;
|
||||
|
||||
void renderImage(Canvas & target, bool reachableToday, size_t imageIndex);
|
||||
void renderImageCross(Canvas & target, bool reachableToday, const int3 & curr);
|
||||
void renderImageArrow(Canvas & target, bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next);
|
||||
size_t selectImageReachability(bool reachableToday, size_t imageIndex);
|
||||
size_t selectImageCross(bool reachableToday, const int3 & curr);
|
||||
size_t selectImageArrow(bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next);
|
||||
size_t selectImage(const IMapRendererContext & context, const int3 & coordinates);
|
||||
|
||||
public:
|
||||
MapRendererPath();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -122,6 +136,7 @@ class MapRendererDebug
|
||||
public:
|
||||
MapRendererDebug();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -131,6 +146,7 @@ class MapRendererOverlay
|
||||
public:
|
||||
MapRendererOverlay();
|
||||
|
||||
uint8_t checksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
||||
@ -146,5 +162,9 @@ class MapRenderer
|
||||
MapRendererDebug rendererDebug;
|
||||
|
||||
public:
|
||||
using TileChecksum = std::array<uint8_t, 8>;
|
||||
|
||||
TileChecksum getTileChecksum(const IMapRendererContext & context, const int3 & coordinates);
|
||||
|
||||
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
|
||||
};
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "MapViewModel.h"
|
||||
#include "MapViewCache.h"
|
||||
#include "MapViewController.h"
|
||||
#include "MapRendererContext.h"
|
||||
#include "mapHandler.h"
|
||||
|
||||
#include "../adventureMap/CAdvMapInt.h"
|
||||
@ -48,8 +47,7 @@ std::shared_ptr<MapViewModel> MapView::createModel(const Point & dimensions) con
|
||||
|
||||
MapView::MapView(const Point & offset, const Point & dimensions)
|
||||
: model(createModel(dimensions))
|
||||
, context(new MapRendererContext())
|
||||
, controller(new MapViewController(context, model))
|
||||
, controller(new MapViewController(model))
|
||||
, tilesCache(new MapViewCache(model))
|
||||
{
|
||||
pos += offset;
|
||||
@ -65,8 +63,8 @@ void MapView::show(SDL_Surface * to)
|
||||
CSDL_Ext::CClipRectGuard guard(to, pos);
|
||||
|
||||
controller->update(GH.mainFPSmng->getElapsedMilliseconds());
|
||||
tilesCache->update(context);
|
||||
tilesCache->render(context, targetClipped);
|
||||
tilesCache->update(controller->getContext());
|
||||
tilesCache->render(controller->getContext(), targetClipped);
|
||||
}
|
||||
|
||||
void MapView::showAll(SDL_Surface * to)
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "../gui/CIntObject.h"
|
||||
|
||||
class MapRendererContext;
|
||||
class MapViewController;
|
||||
class MapViewModel;
|
||||
class MapViewCache;
|
||||
@ -20,7 +19,6 @@ class MapViewCache;
|
||||
class MapView : public CIntObject
|
||||
{
|
||||
std::shared_ptr<MapViewModel> model;
|
||||
std::shared_ptr<MapRendererContext> context;
|
||||
std::unique_ptr<MapViewCache> tilesCache;
|
||||
std::shared_ptr<MapViewController> controller;
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "MapViewCache.h"
|
||||
|
||||
#include "IMapRendererContext.h"
|
||||
#include "MapRenderer.h"
|
||||
#include "MapViewModel.h"
|
||||
|
||||
@ -24,6 +25,7 @@ MapViewCache::~MapViewCache() = default;
|
||||
|
||||
MapViewCache::MapViewCache(const std::shared_ptr<MapViewModel> & model)
|
||||
: model(model)
|
||||
, cachedLevel(0)
|
||||
, mapRenderer(new MapRenderer())
|
||||
, iconsStorage(new CAnimation("VwSymbol"))
|
||||
, intermediate(new Canvas(Point(32, 32)))
|
||||
@ -32,6 +34,9 @@ MapViewCache::MapViewCache(const std::shared_ptr<MapViewModel> & model)
|
||||
iconsStorage->preload();
|
||||
for(size_t i = 0; i < iconsStorage->size(); ++i)
|
||||
iconsStorage->getImage(i)->setBlitMode(EImageBlitMode::COLORKEY);
|
||||
|
||||
Point visibleSize = model->getTilesVisibleDimensions();
|
||||
terrainChecksum.resize(boost::extents[visibleSize.x][visibleSize.y]);
|
||||
}
|
||||
|
||||
Canvas MapViewCache::getTile(const int3 & coordinates)
|
||||
@ -39,7 +44,7 @@ Canvas MapViewCache::getTile(const int3 & coordinates)
|
||||
return Canvas(*terrain, model->getCacheTileArea(coordinates));
|
||||
}
|
||||
|
||||
std::shared_ptr<IImage> MapViewCache::getOverlayImageForTile(const std::shared_ptr<MapRendererContext> & context, const int3 & coordinates)
|
||||
std::shared_ptr<IImage> MapViewCache::getOverlayImageForTile(const std::shared_ptr<const IMapRendererContext> & context, const int3 & coordinates)
|
||||
{
|
||||
size_t imageIndex = context->overlayImageIndex(coordinates);
|
||||
|
||||
@ -48,8 +53,28 @@ std::shared_ptr<IImage> MapViewCache::getOverlayImageForTile(const std::shared_p
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MapViewCache::updateTile(const std::shared_ptr<MapRendererContext> & context, const int3 & coordinates)
|
||||
void MapViewCache::updateTile(const std::shared_ptr<const IMapRendererContext> & context, const int3 & coordinates)
|
||||
{
|
||||
int cacheX = (terrainChecksum.shape()[0] + coordinates.x) % terrainChecksum.shape()[0];
|
||||
int cacheY = (terrainChecksum.shape()[1] + coordinates.y) % terrainChecksum.shape()[1];
|
||||
|
||||
auto & oldCacheEntry = terrainChecksum[cacheX][cacheY];
|
||||
TileChecksum newCacheEntry;
|
||||
|
||||
newCacheEntry.tileX = coordinates.x;
|
||||
newCacheEntry.tileY = coordinates.y;
|
||||
newCacheEntry.checksum = mapRenderer->getTileChecksum(*context, coordinates);
|
||||
|
||||
if (cachedLevel == coordinates.z && oldCacheEntry == newCacheEntry)
|
||||
{
|
||||
// debug code to check caching - cached tiles will slowly fade to black
|
||||
//static const auto overlay = IImage::createFromFile("debug/cached");
|
||||
//Canvas target = getTile(coordinates);
|
||||
//target.draw(overlay, Point(0,0));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Canvas target = getTile(coordinates);
|
||||
|
||||
if(model->getSingleTileSize() == Point(32, 32))
|
||||
@ -61,18 +86,29 @@ void MapViewCache::updateTile(const std::shared_ptr<MapRendererContext> & contex
|
||||
mapRenderer->renderTile(*context, *intermediate, coordinates);
|
||||
target.drawScaled(*intermediate, Point(0, 0), model->getSingleTileSize());
|
||||
}
|
||||
|
||||
oldCacheEntry = newCacheEntry;
|
||||
}
|
||||
|
||||
void MapViewCache::update(const std::shared_ptr<MapRendererContext> & context)
|
||||
void MapViewCache::update(const std::shared_ptr<const IMapRendererContext> & context)
|
||||
{
|
||||
Rect dimensions = model->getTilesTotalRect();
|
||||
|
||||
if (dimensions.w != terrainChecksum.shape()[0] || dimensions.h != terrainChecksum.shape()[1])
|
||||
{
|
||||
boost::multi_array<TileChecksum, 2> newCache;
|
||||
newCache.resize(boost::extents[dimensions.w][dimensions.h]);
|
||||
std::swap(newCache, terrainChecksum);
|
||||
}
|
||||
|
||||
for(int y = dimensions.top(); y < dimensions.bottom(); ++y)
|
||||
for(int x = dimensions.left(); x < dimensions.right(); ++x)
|
||||
updateTile(context, {x, y, model->getLevel()});
|
||||
|
||||
cachedLevel = model->getLevel();
|
||||
}
|
||||
|
||||
void MapViewCache::render(const std::shared_ptr<MapRendererContext> & context, Canvas & target)
|
||||
void MapViewCache::render(const std::shared_ptr<const IMapRendererContext> & context, Canvas & target)
|
||||
{
|
||||
Rect dimensions = model->getTilesTotalRect();
|
||||
|
||||
|
@ -17,14 +17,28 @@ class IImage;
|
||||
class CAnimation;
|
||||
class Canvas;
|
||||
class MapRenderer;
|
||||
class MapRendererContext;
|
||||
//class MapViewController;
|
||||
class IMapRendererContext;
|
||||
class MapViewModel;
|
||||
|
||||
/// Class responsible for rendering of entire map view
|
||||
/// uses rendering parameters provided by owner class
|
||||
class MapViewCache
|
||||
{
|
||||
struct TileChecksum
|
||||
{
|
||||
int tileX = std::numeric_limits<int>::min();
|
||||
int tileY = std::numeric_limits<int>::min();
|
||||
std::array<uint8_t, 8> checksum {};
|
||||
|
||||
bool operator == (const TileChecksum & other) const
|
||||
{
|
||||
return tileX == other.tileX && tileY == other.tileY && checksum == other.checksum;
|
||||
}
|
||||
};
|
||||
|
||||
boost::multi_array<TileChecksum, 2> terrainChecksum;
|
||||
int cachedLevel;
|
||||
|
||||
std::shared_ptr<MapViewModel> model;
|
||||
|
||||
std::unique_ptr<Canvas> terrain;
|
||||
@ -35,16 +49,16 @@ class MapViewCache
|
||||
std::unique_ptr<CAnimation> iconsStorage;
|
||||
|
||||
Canvas getTile(const int3 & coordinates);
|
||||
void updateTile(const std::shared_ptr<MapRendererContext> & context, const int3 & coordinates);
|
||||
void updateTile(const std::shared_ptr<const IMapRendererContext> & context, const int3 & coordinates);
|
||||
|
||||
std::shared_ptr<IImage> getOverlayImageForTile(const std::shared_ptr<MapRendererContext> & context, const int3 & coordinates);
|
||||
std::shared_ptr<IImage> getOverlayImageForTile(const std::shared_ptr<const IMapRendererContext> & context, const int3 & coordinates);
|
||||
public:
|
||||
explicit MapViewCache(const std::shared_ptr<MapViewModel> & model);
|
||||
~MapViewCache();
|
||||
|
||||
/// updates internal terrain cache according to provided time delta
|
||||
void update(const std::shared_ptr<MapRendererContext> & context);
|
||||
void update(const std::shared_ptr<const IMapRendererContext> & context);
|
||||
|
||||
/// renders updated terrain cache onto provided canvas
|
||||
void render(const std::shared_ptr<MapRendererContext> &context, Canvas & target);
|
||||
void render(const std::shared_ptr<const IMapRendererContext> &context, Canvas & target);
|
||||
};
|
||||
|
@ -41,12 +41,17 @@ void MapViewController::setTileSize(const Point & tileSize)
|
||||
model->setTileSize(tileSize);
|
||||
}
|
||||
|
||||
MapViewController::MapViewController(std::shared_ptr<MapRendererContext> context, std::shared_ptr<MapViewModel> model)
|
||||
: context(std::move(context))
|
||||
MapViewController::MapViewController(std::shared_ptr<MapViewModel> model)
|
||||
: context(new MapRendererContext())
|
||||
, model(std::move(model))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<const IMapRendererContext> MapViewController::getContext() const
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
void MapViewController::update(uint32_t timeDelta)
|
||||
{
|
||||
// confirmed to match H3 for
|
||||
|
@ -17,6 +17,7 @@ struct ObjectPosInfo;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class MapViewModel;
|
||||
class IMapRendererContext;
|
||||
class MapRendererContext;
|
||||
|
||||
/// Class responsible for updating view state,
|
||||
@ -38,7 +39,9 @@ private:
|
||||
void onHeroRotated(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
|
||||
|
||||
public:
|
||||
MapViewController(std::shared_ptr<MapRendererContext> context, std::shared_ptr<MapViewModel> model);
|
||||
explicit MapViewController(std::shared_ptr<MapViewModel> model);
|
||||
|
||||
std::shared_ptr<const IMapRendererContext> getContext() const;
|
||||
|
||||
void setViewCenter(const int3 & position);
|
||||
void setViewCenter(const Point & position, int level);
|
||||
|
Loading…
Reference in New Issue
Block a user