MapView.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * MapView.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "MapView.h"
  12. #include "MapRenderer.h"
  13. #include "mapHandler.h"
  14. #include "CAdvMapInt.h"
  15. #include "../CGameInfo.h"
  16. #include "../CMusicHandler.h"
  17. #include "../CPlayerInterface.h"
  18. #include "../gui/CGuiHandler.h"
  19. #include "../render/CAnimation.h"
  20. #include "../render/CFadeAnimation.h"
  21. #include "../render/Canvas.h"
  22. #include "../render/Colors.h"
  23. #include "../render/Graphics.h"
  24. #include "../render/IImage.h"
  25. #include "../renderSDL/SDL_Extensions.h"
  26. #include "../../CCallback.h"
  27. #include "../../lib/CConfigHandler.h"
  28. #include "../../lib/CGeneralTextHandler.h"
  29. #include "../../lib/CRandomGenerator.h"
  30. #include "../../lib/CStopWatch.h"
  31. #include "../../lib/Color.h"
  32. #include "../../lib/RiverHandler.h"
  33. #include "../../lib/RoadHandler.h"
  34. #include "../../lib/TerrainHandler.h"
  35. #include "../../lib/mapObjects/CGHeroInstance.h"
  36. #include "../../lib/mapObjects/CObjectClassesHandler.h"
  37. #include "../../lib/mapping/CMap.h"
  38. MapCache::~MapCache() = default;
  39. MapCache::MapCache(const Point & tileSize, const Point & dimensions)
  40. : tileSize(tileSize)
  41. , context(new MapRendererContext())
  42. , mapRenderer(new MapRenderer(*context))
  43. , targetDimensionsPixels(dimensions)
  44. , viewCenter(0, 0)
  45. , mapLevel(0)
  46. {
  47. // total number of potentially visible tiles is:
  48. // 1) number of completely visible tiles
  49. // 2) additional tile that might be partially visible from left/top size
  50. // 3) additional tile that might be partially visible from right/bottom size
  51. Point visibleTiles{
  52. dimensions.x / tileSize.x + 2,
  53. dimensions.y / tileSize.y + 2,
  54. };
  55. viewDimensionsTiles = visibleTiles;
  56. viewDimensionsPixels = visibleTiles * tileSize;
  57. terrain = std::make_unique<Canvas>(viewDimensionsPixels);
  58. }
  59. void MapCache::setViewCenter(const Point & center, int newLevel)
  60. {
  61. viewCenter = center;
  62. mapLevel = newLevel;
  63. int3 mapSize = LOCPLINT->cb->getMapSize();
  64. Point viewMax = Point(mapSize) * tileSize;
  65. vstd::abetween(viewCenter.x, 0, viewMax.x);
  66. vstd::abetween(viewCenter.y, 0, viewMax.y);
  67. }
  68. Canvas MapCache::getTile(const int3 & coordinates)
  69. {
  70. assert(mapLevel == coordinates.z);
  71. assert(viewDimensionsTiles.x + coordinates.x >= 0);
  72. assert(viewDimensionsTiles.y + coordinates.y >= 0);
  73. Point tileIndex{
  74. (viewDimensionsTiles.x + coordinates.x) % viewDimensionsTiles.x,
  75. (viewDimensionsTiles.y + coordinates.y) % viewDimensionsTiles.y
  76. };
  77. Rect terrainSection(tileIndex * tileSize, tileSize);
  78. return Canvas(*terrain, terrainSection);
  79. }
  80. void MapCache::updateTile(const int3 & coordinates)
  81. {
  82. Canvas target = getTile(coordinates);
  83. mapRenderer->renderTile(*context, target, coordinates);
  84. }
  85. Rect MapCache::getVisibleAreaTiles() const
  86. {
  87. Rect visibleAreaPixels = {
  88. viewCenter.x - targetDimensionsPixels.x / 2,
  89. viewCenter.y - targetDimensionsPixels.y / 2,
  90. targetDimensionsPixels.x,
  91. targetDimensionsPixels.y
  92. };
  93. // NOTE: use division via double in order to use floor (which rounds to negative infinity and not towards zero)
  94. Point topLeftTile{
  95. static_cast<int>(std::floor(static_cast<double>(visibleAreaPixels.left()) / tileSize.x)),
  96. static_cast<int>(std::floor(static_cast<double>(visibleAreaPixels.top()) / tileSize.y)),
  97. };
  98. Point bottomRightTile{
  99. visibleAreaPixels.right() / tileSize.x,
  100. visibleAreaPixels.bottom() / tileSize.y
  101. };
  102. return Rect(topLeftTile, bottomRightTile - topLeftTile + Point(1, 1));
  103. }
  104. int3 MapCache::getTileAtPoint(const Point & position) const
  105. {
  106. Point topLeftOffset = viewCenter - targetDimensionsPixels / 2;
  107. Point absolutePosition = position + topLeftOffset;
  108. return {
  109. static_cast<int>(std::floor(static_cast<double>(absolutePosition.x) / tileSize.x)),
  110. static_cast<int>(std::floor(static_cast<double>(absolutePosition.y) / tileSize.y)),
  111. mapLevel
  112. };
  113. }
  114. int3 MapCache::getTileCenter() const
  115. {
  116. return getTileAtPoint(getViewCenter());
  117. }
  118. Point MapCache::getViewCenter() const
  119. {
  120. return viewCenter;
  121. }
  122. void MapCache::update(uint32_t timeDelta)
  123. {
  124. context->advanceAnimations(timeDelta);
  125. Rect dimensions = getVisibleAreaTiles();
  126. for(int y = dimensions.top(); y < dimensions.bottom(); ++y)
  127. for(int x = dimensions.left(); x < dimensions.right(); ++x)
  128. updateTile({x, y, mapLevel});
  129. }
  130. void MapCache::render(Canvas & target)
  131. {
  132. update(GH.mainFPSmng->getElapsedMilliseconds());
  133. Rect dimensions = getVisibleAreaTiles();
  134. for(int y = dimensions.top(); y < dimensions.bottom(); ++y)
  135. {
  136. for(int x = dimensions.left(); x < dimensions.right(); ++x)
  137. {
  138. Point topLeftOffset = viewCenter - targetDimensionsPixels / 2;
  139. Point tilePosAbsolute = Point(x, y) * tileSize;
  140. Point tilePosRelative = tilePosAbsolute - topLeftOffset;
  141. Canvas source = getTile(int3(x, y, mapLevel));
  142. target.draw(source, tilePosRelative);
  143. }
  144. }
  145. }
  146. MapView::MapView(const Point & offset, const Point & dimensions)
  147. : tilesCache(new MapCache(Point(32, 32), dimensions))
  148. , tileSize(Point(32, 32))
  149. {
  150. pos += offset;
  151. pos.w = dimensions.x;
  152. pos.h = dimensions.y;
  153. }
  154. Rect MapView::getVisibleAreaTiles() const
  155. {
  156. return tilesCache->getVisibleAreaTiles();
  157. }
  158. int3 MapView::getTileCenter() const
  159. {
  160. return tilesCache->getTileCenter();
  161. }
  162. int3 MapView::getTileAtPoint(const Point & position) const
  163. {
  164. return tilesCache->getTileAtPoint(position);
  165. }
  166. Point MapView::getViewCenter() const
  167. {
  168. return tilesCache->getViewCenter();
  169. }
  170. void MapView::setViewCenter(const int3 & position)
  171. {
  172. setViewCenter(Point(position.x, position.y) * tileSize, position.z);
  173. }
  174. void MapView::setViewCenter(const Point & position, int level)
  175. {
  176. tilesCache->setViewCenter(position, level);
  177. }
  178. void MapView::show(SDL_Surface * to)
  179. {
  180. Canvas target(to);
  181. Canvas targetClipped(target, pos);
  182. CSDL_Ext::CClipRectGuard guard(to, pos);
  183. tilesCache->render(targetClipped);
  184. }
  185. void MapView::showAll(SDL_Surface * to)
  186. {
  187. show(to);
  188. }
  189. void MapRendererContext::advanceAnimations(uint32_t ms)
  190. {
  191. animationTime += ms;
  192. }
  193. int3 MapRendererContext::getMapSize() const
  194. {
  195. return LOCPLINT->cb->getMapSize();
  196. }
  197. bool MapRendererContext::isInMap(const int3 & coordinates) const
  198. {
  199. return LOCPLINT->cb->isInTheMap(coordinates);
  200. }
  201. const TerrainTile & MapRendererContext::getMapTile(const int3 & coordinates) const
  202. {
  203. return CGI->mh->map->getTile(coordinates);
  204. }
  205. MapRendererContext::ObjectsVector MapRendererContext::getAllObjects() const
  206. {
  207. return CGI->mh->map->objects;
  208. }
  209. const CGObjectInstance * MapRendererContext::getObject(ObjectInstanceID objectID) const
  210. {
  211. return CGI->mh->map->objects.at(objectID.getNum());
  212. }
  213. bool MapRendererContext::isVisible(const int3 & coordinates) const
  214. {
  215. return LOCPLINT->cb->isVisible(coordinates) || settings["session"]["spectate"].Bool();
  216. }
  217. const CGPath * MapRendererContext::currentPath() const
  218. {
  219. const auto * hero = adventureInt->curHero();
  220. if(!hero)
  221. return nullptr;
  222. if(!LOCPLINT->paths.hasPath(hero))
  223. return nullptr;
  224. return &LOCPLINT->paths.getPath(hero);
  225. }
  226. uint32_t MapRendererContext::getAnimationPeriod() const
  227. {
  228. // H3 timing for adventure map objects animation is 180 ms
  229. // Terrain animations also use identical interval, however it is only present in HotA and/or HD Mod
  230. // TODO: duration of fade-in/fade-out for teleport, entering/leaving boat, removal of objects
  231. // TOOD: duration of hero movement animation, frame timing of hero movement animation, effect of hero speed option
  232. // TOOD: duration of enemy hero movement animation, frame timing of enemy hero movement animation, effect of enemy hero speed option
  233. return 180;
  234. }
  235. uint32_t MapRendererContext::getAnimationTime() const
  236. {
  237. return animationTime;
  238. }
  239. Point MapRendererContext::tileSize() const
  240. {
  241. return Point(32, 32);
  242. }
  243. bool MapRendererContext::showGrid() const
  244. {
  245. return true; // settings["session"]["showGrid"].Bool();
  246. }