MapView.cpp 7.8 KB

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