2009-04-15 17:03:31 +03:00
/*
* mapHandler . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
2009-04-16 14:14:13 +03:00
*/
2017-07-13 10:26:03 +02:00
# pragma once
# include "../lib/int3.h"
# include "../lib/spells/ViewSpellInt.h"
# include "gui/Geometries.h"
# include "SDL.h"
2009-04-16 14:14:13 +03:00
class CGObjectInstance ;
class CGHeroInstance ;
2015-02-09 17:03:24 +02:00
class CGBoat ;
2012-11-03 22:31:16 +03:00
class CMap ;
2009-04-16 14:14:13 +03:00
struct TerrainTile ;
struct SDL_Surface ;
2015-01-17 00:44:40 +02:00
struct SDL_Rect ;
2016-10-18 05:32:58 +02:00
class CAnimation ;
class IImage ;
2015-01-31 00:37:28 +02:00
class CFadeAnimation ;
2015-02-09 17:03:24 +02:00
class PlayerColor ;
2009-04-16 14:14:13 +03:00
2015-01-13 21:57:41 +02:00
enum class EWorldViewIcon
{
TOWN = 0 ,
HERO ,
ARTIFACT ,
TELEPORT ,
GATE ,
MINE_WOOD ,
MINE_MERCURY ,
MINE_STONE ,
MINE_SULFUR ,
MINE_CRYSTAL ,
MINE_GEM ,
MINE_GOLD ,
RES_WOOD ,
RES_MERCURY ,
RES_STONE ,
RES_SULFUR ,
RES_CRYSTAL ,
RES_GEM ,
RES_GOLD ,
} ;
2015-01-28 21:07:57 +02:00
enum class EMapObjectFadingType
{
NONE ,
IN ,
OUT
} ;
2015-01-31 00:37:28 +02:00
enum class EMapAnimRedrawStatus
{
OK ,
REDRAW_REQUESTED // map blitter requests quick redraw due to current animation
} ;
2015-01-28 21:07:57 +02:00
struct TerrainTileObject
{
const CGObjectInstance * obj ;
SDL_Rect rect ;
2015-01-31 00:37:28 +02:00
int fadeAnimKey ;
2017-09-14 19:46:38 +02:00
boost : : optional < std : : string > ambientSound ;
2016-10-18 05:32:58 +02:00
2017-09-14 19:46:38 +02:00
TerrainTileObject ( const CGObjectInstance * obj_ , SDL_Rect rect_ , bool visitablePos = false ) ;
2015-01-31 00:37:28 +02:00
~ TerrainTileObject ( ) ;
2015-01-28 21:07:57 +02:00
} ;
2009-04-16 14:14:13 +03:00
struct TerrainTile2
{
2015-01-28 21:07:57 +02:00
std : : vector < TerrainTileObject > objects ; //pointers to objects being on this tile with rects to be easier to blit this tile on screen
2009-04-16 14:14:13 +03:00
} ;
2015-01-18 19:53:40 +02:00
struct MapDrawingInfo
{
bool scaled ;
int3 & topTile ; // top-left tile in viewport [in tiles]
const std : : vector < std : : vector < std : : vector < ui8 > > > * visibilityMap ;
SDL_Rect * drawBounds ; // map rect drawing bounds on screen
2016-10-18 05:32:58 +02:00
std : : shared_ptr < CAnimation > icons ; // holds overlay icons for world view mode
2015-01-18 19:53:40 +02:00
float scale ; // map scale for world view mode (only if scaled == true)
bool otherheroAnim ;
ui8 anim ;
ui8 heroAnim ;
int3 movement ; // used for smooth map movement
bool puzzleMode ;
int3 grailPos ; // location of grail for puzzle mode [in tiles]
2016-10-18 05:32:58 +02:00
2015-02-26 16:15:17 +02:00
const std : : vector < ObjectPosInfo > * additionalIcons ;
2016-10-18 05:32:58 +02:00
2015-02-02 14:02:27 +02:00
bool showAllTerrain ; //for expert viewEarth
2016-10-18 05:32:58 +02:00
MapDrawingInfo ( int3 & topTile_ , const std : : vector < std : : vector < std : : vector < ui8 > > > * visibilityMap_ , SDL_Rect * drawBounds_ , std : : shared_ptr < CAnimation > icons_ = nullptr )
2015-01-18 19:53:40 +02:00
: scaled ( false ) ,
topTile ( topTile_ ) ,
visibilityMap ( visibilityMap_ ) ,
drawBounds ( drawBounds_ ) ,
2016-10-18 05:32:58 +02:00
icons ( icons_ ) ,
2015-01-18 19:53:40 +02:00
scale ( 1.0f ) ,
otherheroAnim ( false ) ,
anim ( 0u ) ,
heroAnim ( 0u ) ,
movement ( int3 ( ) ) ,
puzzleMode ( false ) ,
2015-02-02 14:02:27 +02:00
grailPos ( int3 ( ) ) ,
2015-02-26 16:15:17 +02:00
additionalIcons ( nullptr ) ,
2015-02-02 14:02:27 +02:00
showAllTerrain ( false )
2015-01-18 19:53:40 +02:00
{ }
ui8 getHeroAnim ( ) const { return otherheroAnim ? anim : heroAnim ; }
} ;
2009-04-16 14:14:13 +03:00
template < typename T > class PseudoV
{
public :
2013-12-20 16:07:58 +03:00
PseudoV ( ) : offset ( 0 ) { }
2009-04-16 14:14:13 +03:00
inline T & operator [ ] ( const int & n )
{
return inver [ n + offset ] ;
}
inline const T & operator [ ] ( const int & n ) const
{
return inver [ n + offset ] ;
}
2009-06-12 06:26:41 +03:00
void resize ( int rest , int before , int after )
2009-04-16 14:14:13 +03:00
{
2009-06-12 06:26:41 +03:00
inver . resize ( before + rest + after ) ;
offset = before ;
2009-04-16 14:14:13 +03:00
}
int size ( ) const
{
return inver . size ( ) ;
}
2013-12-20 16:07:58 +03:00
private :
int offset ;
std : : vector < T > inver ;
2009-04-16 14:14:13 +03:00
} ;
class CMapHandler
{
2016-11-07 23:19:53 +02:00
enum class EMapCacheType : ui8
2015-01-13 21:57:41 +02:00
{
2016-11-07 23:19:53 +02:00
TERRAIN , OBJECTS , ROADS , RIVERS , FOW , HEROES , HERO_FLAGS , FRAME , AFTER_LAST
2015-01-13 21:57:41 +02:00
} ;
2016-11-08 21:14:38 +02:00
/// temporarily caches rescaled frames for map world view redrawing
2015-01-13 21:57:41 +02:00
class CMapCache
{
2018-04-07 13:34:11 +02:00
std : : array < std : : map < intptr_t , std : : shared_ptr < IImage > > , ( ui8 ) EMapCacheType : : AFTER_LAST > data ;
2015-01-13 21:57:41 +02:00
float worldViewCachedScale ;
public :
2016-11-27 16:48:18 +02:00
CMapCache ( ) ;
2015-01-13 21:57:41 +02:00
/// destroys all cached data (frees surfaces)
void discardWorldViewCache ( ) ;
/// updates scale and determines if currently cached data is still valid
void updateWorldViewScale ( float scale ) ;
2016-11-08 21:14:38 +02:00
/// asks for cached data; @returns cached data if found, new scaled surface otherwise, may return nullptr in case of scaling error
2018-04-07 13:34:11 +02:00
std : : shared_ptr < IImage > requestWorldViewCacheOrCreate ( EMapCacheType type , std : : shared_ptr < IImage > fullSurface ) ;
2015-01-13 21:57:41 +02:00
} ;
2016-10-18 05:32:58 +02:00
2016-11-08 21:14:38 +02:00
/// helper struct to pass around resolved bitmaps of an object; images can be nullptr if object doesn't have bitmap of that type
2015-02-09 17:03:24 +02:00
struct AnimBitmapHolder
{
2018-04-07 13:34:11 +02:00
std : : shared_ptr < IImage > objBitmap ; // main object bitmap
std : : shared_ptr < IImage > flagBitmap ; // flag bitmap for the object (probably only for heroes and boats with heroes)
2015-02-09 17:03:24 +02:00
bool isMoving ; // indicates if the object is moving (again, heroes/boats only)
2016-10-18 05:32:58 +02:00
2018-04-07 13:34:11 +02:00
AnimBitmapHolder ( std : : shared_ptr < IImage > objBitmap_ = nullptr , std : : shared_ptr < IImage > flagBitmap_ = nullptr , bool moving = false )
2015-02-09 17:03:24 +02:00
: objBitmap ( objBitmap_ ) ,
flagBitmap ( flagBitmap_ ) ,
isMoving ( moving )
{ }
} ;
2015-01-13 21:57:41 +02:00
2015-01-18 19:53:40 +02:00
class CMapBlitter
2016-10-18 05:32:58 +02:00
{
2015-01-18 19:53:40 +02:00
protected :
2015-02-18 16:31:55 +02:00
const int FRAMES_PER_MOVE_ANIM_GROUP = 8 ;
2015-01-19 21:08:19 +02:00
CMapHandler * parent ; // ptr to enclosing map handler; generally for legacy reasons, probably could/should be refactored out of here
int tileSize ; // size of a tile drawn on map [in pixels]
int halfTileSizeCeil ; // half of the tile size, rounded up
int3 tileCount ; // number of tiles in current viewport
int3 topTile ; // top-left tile of the viewport
int3 initPos ; // starting drawing position [in pixels]
int3 pos ; // current position [in tiles]
int3 realPos ; // current position [in pixels]
Rect realTileRect ; // default rect based on current pos: [realPos.x, realPos.y, tileSize, tileSize]
Rect defaultTileRect ; // default rect based on 0: [0, 0, tileSize, tileSize]
const MapDrawingInfo * info ; // data for drawing passed from outside
/// general drawing method, called internally by more specialized ones
2018-04-07 13:34:11 +02:00
virtual void drawElement ( EMapCacheType cacheType , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , SDL_Surface * targetSurf , SDL_Rect * destRect ) const = 0 ;
2016-11-04 16:05:56 +02:00
2015-01-19 21:08:19 +02:00
// first drawing pass
/// draws terrain bitmap (or custom bitmap if applicable) on current tile
virtual void drawTileTerrain ( SDL_Surface * targetSurf , const TerrainTile & tinfo , const TerrainTile2 & tile ) const ;
/// draws a river segment on current tile
virtual void drawRiver ( SDL_Surface * targetSurf , const TerrainTile & tinfo ) const ;
/// draws a road segment on current tile
virtual void drawRoad ( SDL_Surface * targetSurf , const TerrainTile & tinfo , const TerrainTile * tinfoUpper ) const ;
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
virtual void drawObjects ( SDL_Surface * targetSurf , const TerrainTile2 & tile ) const ;
2018-04-07 13:34:11 +02:00
virtual void drawObject ( SDL_Surface * targetSurf , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , bool moving ) const ;
virtual void drawHeroFlag ( SDL_Surface * targetSurf , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , SDL_Rect * destRect , bool moving ) const ;
2015-01-19 21:08:19 +02:00
// second drawing pass
/// current tile: draws overlay over the map, used to draw world view icons
virtual void drawTileOverlay ( SDL_Surface * targetSurf , const TerrainTile2 & tile ) const = 0 ;
/// draws fog of war on current tile
virtual void drawFow ( SDL_Surface * targetSurf ) const ;
/// draws map border frame on current position
virtual void drawFrame ( SDL_Surface * targetSurf ) const ;
2015-02-26 16:15:17 +02:00
/// draws additional icons (for VIEW_AIR, VIEW_EARTH spells atm)
virtual void drawOverlayEx ( SDL_Surface * targetSurf ) ;
2015-01-19 21:08:19 +02:00
// third drawing pass
/// custom post-processing, if needed (used by puzzle view)
virtual void postProcessing ( SDL_Surface * targetSurf ) const { }
// misc methods
/// initializes frame-drawing (called at the start of every redraw)
virtual void init ( const MapDrawingInfo * drawingInfo ) = 0 ;
/// calculates clip region for map viewport
virtual SDL_Rect clip ( SDL_Surface * targetSurf ) const = 0 ;
2016-11-07 23:19:53 +02:00
virtual ui8 getHeroFrameGroup ( ui8 dir , bool isMoving ) const ;
2015-01-19 21:08:19 +02:00
virtual ui8 getPhaseShift ( const CGObjectInstance * object ) const ;
virtual bool canDrawObject ( const CGObjectInstance * obj ) const ;
virtual bool canDrawCurrentTile ( ) const ;
2016-10-18 05:32:58 +02:00
2015-02-09 17:03:24 +02:00
// internal helper methods to choose correct bitmap(s) for object; called internally by findObjectBitmap
AnimBitmapHolder findHeroBitmap ( const CGHeroInstance * hero , int anim ) const ;
2016-10-18 05:32:58 +02:00
AnimBitmapHolder findBoatBitmap ( const CGBoat * hero , int anim ) const ;
2018-04-07 13:34:11 +02:00
std : : shared_ptr < IImage > findFlagBitmap ( const CGHeroInstance * obj , int anim , const PlayerColor * color , int group ) const ;
std : : shared_ptr < IImage > findHeroFlagBitmap ( const CGHeroInstance * obj , int anim , const PlayerColor * color , int group ) const ;
std : : shared_ptr < IImage > findBoatFlagBitmap ( const CGBoat * obj , int anim , const PlayerColor * color , int group , ui8 dir ) const ;
std : : shared_ptr < IImage > findFlagBitmapInternal ( std : : shared_ptr < CAnimation > animation , int anim , int group , ui8 dir , bool moving ) const ;
2016-10-18 05:32:58 +02:00
2015-01-18 19:53:40 +02:00
public :
2016-11-26 21:33:08 +02:00
CMapBlitter ( CMapHandler * p ) ;
virtual ~ CMapBlitter ( ) ;
2015-01-19 21:08:19 +02:00
void blit ( SDL_Surface * targetSurf , const MapDrawingInfo * info ) ;
2015-02-09 17:03:24 +02:00
/// helper method that chooses correct bitmap(s) for given object
AnimBitmapHolder findObjectBitmap ( const CGObjectInstance * obj , int anim ) const ;
2015-01-18 19:53:40 +02:00
} ;
class CMapNormalBlitter : public CMapBlitter
{
protected :
2018-04-07 13:34:11 +02:00
void drawElement ( EMapCacheType cacheType , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , SDL_Surface * targetSurf , SDL_Rect * destRect ) const override ;
2015-01-19 21:08:19 +02:00
void drawTileOverlay ( SDL_Surface * targetSurf , const TerrainTile2 & tile ) const override { }
void init ( const MapDrawingInfo * info ) override ;
SDL_Rect clip ( SDL_Surface * targetSurf ) const override ;
2015-01-18 19:53:40 +02:00
public :
CMapNormalBlitter ( CMapHandler * parent ) ;
virtual ~ CMapNormalBlitter ( ) { }
} ;
class CMapWorldViewBlitter : public CMapBlitter
{
2015-02-26 16:15:17 +02:00
private :
2018-04-07 13:34:11 +02:00
std : : shared_ptr < IImage > objectToIcon ( Obj id , si32 subId , PlayerColor owner ) const ;
2015-01-18 19:53:40 +02:00
protected :
2018-04-07 13:34:11 +02:00
void drawElement ( EMapCacheType cacheType , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , SDL_Surface * targetSurf , SDL_Rect * destRect ) const override ;
2015-01-19 21:08:19 +02:00
void drawTileOverlay ( SDL_Surface * targetSurf , const TerrainTile2 & tile ) const override ;
2018-04-07 13:34:11 +02:00
void drawHeroFlag ( SDL_Surface * targetSurf , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , SDL_Rect * destRect , bool moving ) const override ;
void drawObject ( SDL_Surface * targetSurf , std : : shared_ptr < IImage > source , SDL_Rect * sourceRect , bool moving ) const override ;
2015-01-19 21:08:19 +02:00
void drawFrame ( SDL_Surface * targetSurf ) const override { }
2015-10-12 15:47:10 +02:00
void drawOverlayEx ( SDL_Surface * targetSurf ) override ;
2015-01-19 21:08:19 +02:00
void init ( const MapDrawingInfo * info ) override ;
SDL_Rect clip ( SDL_Surface * targetSurf ) const override ;
ui8 getPhaseShift ( const CGObjectInstance * object ) const override { return 0u ; }
void calculateWorldViewCameraPos ( ) ;
2015-01-18 19:53:40 +02:00
public :
CMapWorldViewBlitter ( CMapHandler * parent ) ;
virtual ~ CMapWorldViewBlitter ( ) { }
} ;
2015-01-19 21:08:19 +02:00
class CMapPuzzleViewBlitter : public CMapNormalBlitter
{
std : : vector < int > unblittableObjects ;
void drawObjects ( SDL_Surface * targetSurf , const TerrainTile2 & tile ) const override ;
void drawFow ( SDL_Surface * targetSurf ) const override { } // skipping FoW in puzzle view
void postProcessing ( SDL_Surface * targetSurf ) const override ;
bool canDrawObject ( const CGObjectInstance * obj ) const override ;
bool canDrawCurrentTile ( ) const override { return true ; }
public :
CMapPuzzleViewBlitter ( CMapHandler * parent ) ;
} ;
2015-01-18 19:53:40 +02:00
2015-01-13 21:57:41 +02:00
CMapCache cache ;
2015-01-18 19:53:40 +02:00
CMapBlitter * normalBlitter ;
CMapBlitter * worldViewBlitter ;
2015-01-19 21:08:19 +02:00
CMapBlitter * puzzleViewBlitter ;
2016-10-18 05:32:58 +02:00
2015-01-31 00:37:28 +02:00
std : : map < int , std : : pair < int3 , CFadeAnimation * > > fadeAnims ;
int fadeAnimCounter ;
2015-01-13 21:57:41 +02:00
2015-01-19 21:08:19 +02:00
CMapBlitter * resolveBlitter ( const MapDrawingInfo * info ) const ;
2015-01-31 00:37:28 +02:00
bool updateObjectsFade ( ) ;
2015-02-09 17:03:24 +02:00
bool startObjectFade ( TerrainTileObject & obj , bool in , int3 pos ) ;
2016-11-07 23:19:53 +02:00
void initObjectRects ( ) ;
void initBorderGraphics ( ) ;
void initTerrainGraphics ( ) ;
void prepareFOWDefs ( ) ;
2009-04-16 14:14:13 +03:00
public :
2009-05-07 20:20:41 +03:00
PseudoV < PseudoV < PseudoV < TerrainTile2 > > > ttiles ; //informations about map tiles
2009-06-12 06:26:41 +03:00
int3 sizes ; //map size (x = width, y = height, z = number of levels)
2012-10-26 20:51:05 +03:00
const CMap * map ;
2009-06-14 10:02:06 +03:00
// Max number of tiles that will fit in the map screen. Tiles
// can be partial on each edges.
int tilesW ;
int tilesH ;
// size of each side of the frame around the whole map, in tiles
int frameH ;
int frameW ;
// Coord in pixels of the top left corner of the top left tile to
// draw. Values range is [-31..0]. A negative value
// implies that part of the tile won't be displayed.
int offsetX ;
int offsetY ;
2009-06-12 06:26:41 +03:00
2016-11-07 23:19:53 +02:00
//terrain graphics
2016-11-25 19:59:17 +02:00
//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013
typedef std : : vector < std : : array < std : : shared_ptr < CAnimation > , 4 > > TFlippedAnimations ; //[type, rotation]
2018-04-07 13:34:11 +02:00
typedef std : : vector < std : : vector < std : : array < std : : shared_ptr < IImage > , 4 > > > TFlippedCache ; //[type, view type, rotation]
2016-11-07 23:19:53 +02:00
TFlippedAnimations terrainAnimations ; //[terrain type, rotation]
TFlippedCache terrainImages ; //[terrain type, view type, rotation]
TFlippedAnimations roadAnimations ; //[road type, rotation]
TFlippedCache roadImages ; //[road type, view type, rotation]
2016-11-06 20:39:32 +02:00
2016-11-07 23:19:53 +02:00
TFlippedAnimations riverAnimations ; //[river type, rotation]
TFlippedCache riverImages ; //[river type, view type, rotation]
2016-11-06 03:28:57 +02:00
2016-11-07 23:19:53 +02:00
//Fog of War cache (not owned)
2018-04-07 13:34:11 +02:00
std : : vector < std : : shared_ptr < IImage > > FoWfullHide ;
2016-11-07 23:19:53 +02:00
std : : vector < std : : vector < std : : vector < ui8 > > > hideBitmap ; //frame indexes (in FoWfullHide) of graphic that should be used to fully hide a tile
2018-04-07 13:34:11 +02:00
std : : vector < std : : shared_ptr < IImage > > FoWpartialHide ;
2016-11-07 23:19:53 +02:00
//edge graphics
std : : unique_ptr < CAnimation > egdeAnimation ;
2018-04-07 13:34:11 +02:00
std : : vector < std : : shared_ptr < IImage > > egdeImages ; //cache of links to egdeAnimation (for faster access)
2016-11-07 23:19:53 +02:00
PseudoV < PseudoV < PseudoV < ui8 > > > edgeFrames ; //frame indexes (in egdeImages) of tile outside of map
2011-12-14 00:23:17 +03:00
2013-02-19 01:37:22 +03:00
mutable std : : map < const CGObjectInstance * , ui8 > animationPhase ;
2017-07-17 23:04:00 +02:00
CMapHandler ( ) ;
~ CMapHandler ( ) ;
2009-04-16 14:14:13 +03:00
2010-02-21 17:03:30 +02:00
void getTerrainDescr ( const int3 & pos , std : : string & out , bool terName ) ; //if tername == false => empty string when tile is clear
2016-10-02 16:27:01 +02:00
bool printObject ( const CGObjectInstance * obj , bool fadein = false ) ; //puts appropriate things to tiles, so obj will be visible on map
2015-01-28 21:07:57 +02:00
bool hideObject ( const CGObjectInstance * obj , bool fadeout = false ) ; //removes appropriate things from ttiles, so obj will be no longer visible on map (but still will exist)
2009-04-16 14:14:13 +03:00
void init ( ) ;
2015-01-31 00:37:28 +02:00
EMapAnimRedrawStatus drawTerrainRectNew ( SDL_Surface * targetSurface , const MapDrawingInfo * info , bool redrawOnlyAnim = false ) ;
2009-04-16 14:14:13 +03:00
void updateWater ( ) ;
2015-02-09 17:03:24 +02:00
/// determines if the map is ready to handle new hero movement (not available during fading animations)
bool canStartHeroMovement ( ) ;
2009-04-16 14:14:13 +03:00
2015-01-13 21:57:41 +02:00
void discardWorldViewCache ( ) ;
2014-06-24 02:26:36 +03:00
2015-01-13 21:57:41 +02:00
static bool compareObjectBlitOrder ( const CGObjectInstance * a , const CGObjectInstance * b ) ;
2009-04-16 14:14:13 +03:00
} ;