CCursorHandler.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * CCursorHandler.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 "CCursorHandler.h"
  12. #include <SDL.h>
  13. #include "SDL_Extensions.h"
  14. #include "CGuiHandler.h"
  15. #include "../widgets/Images.h"
  16. #include "../CMT.h"
  17. void CCursorHandler::clearBuffer()
  18. {
  19. CSDL_Ext::fillSurface(buffer, Colors::TRANSPARENT );
  20. }
  21. void CCursorHandler::updateBuffer(CIntObject * payload)
  22. {
  23. payload->moveTo(Point(0,0));
  24. payload->showAll(buffer);
  25. needUpdate = true;
  26. }
  27. void CCursorHandler::replaceBuffer(CIntObject * payload)
  28. {
  29. clearBuffer();
  30. updateBuffer(payload);
  31. }
  32. CCursorHandler::CCursorHandler()
  33. : needUpdate(true)
  34. , buffer(nullptr)
  35. , cursorLayer(nullptr)
  36. , frameTime(0.f)
  37. , showing(false)
  38. {
  39. cursorLayer = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 40, 40);
  40. SDL_SetTextureBlendMode(cursorLayer, SDL_BLENDMODE_BLEND);
  41. xpos = ypos = 0;
  42. type = Cursor::Type::DEFAULT;
  43. dndObject = nullptr;
  44. cursors =
  45. {
  46. std::make_unique<CAnimImage>("CRADVNTR", 0),
  47. std::make_unique<CAnimImage>("CRCOMBAT", 0),
  48. std::make_unique<CAnimImage>("CRDEFLT", 0),
  49. std::make_unique<CAnimImage>("CRSPELL", 0)
  50. };
  51. currentCursor = cursors.at(static_cast<size_t>(Cursor::Type::DEFAULT)).get();
  52. buffer = CSDL_Ext::newSurface(40,40);
  53. SDL_SetSurfaceBlendMode(buffer, SDL_BLENDMODE_NONE);
  54. SDL_ShowCursor(SDL_DISABLE);
  55. set(Cursor::Map::POINTER);
  56. }
  57. Point CCursorHandler::position() const
  58. {
  59. return Point(xpos, ypos);
  60. }
  61. void CCursorHandler::changeGraphic(Cursor::Type type, size_t index)
  62. {
  63. assert(dndObject == nullptr);
  64. if(type != this->type)
  65. {
  66. this->type = type;
  67. this->frame = index;
  68. currentCursor = cursors.at(static_cast<size_t>(type)).get();
  69. currentCursor->setFrame(index);
  70. }
  71. else if(index != this->frame)
  72. {
  73. this->frame = index;
  74. currentCursor->setFrame(index);
  75. }
  76. replaceBuffer(currentCursor);
  77. }
  78. void CCursorHandler::set(Cursor::Default index)
  79. {
  80. changeGraphic(Cursor::Type::DEFAULT, static_cast<size_t>(index));
  81. }
  82. void CCursorHandler::set(Cursor::Map index)
  83. {
  84. changeGraphic(Cursor::Type::ADVENTURE, static_cast<size_t>(index));
  85. }
  86. void CCursorHandler::set(Cursor::Combat index)
  87. {
  88. changeGraphic(Cursor::Type::COMBAT, static_cast<size_t>(index));
  89. }
  90. void CCursorHandler::set(Cursor::Spellcast index)
  91. {
  92. //Note: this is animated cursor, ignore specified frame and only change type
  93. changeGraphic(Cursor::Type::SPELLBOOK, frame);
  94. }
  95. void CCursorHandler::dragAndDropCursor(std::unique_ptr<CAnimImage> object)
  96. {
  97. dndObject = std::move(object);
  98. if(dndObject)
  99. replaceBuffer(dndObject.get());
  100. else
  101. replaceBuffer(currentCursor);
  102. }
  103. void CCursorHandler::cursorMove(const int & x, const int & y)
  104. {
  105. xpos = x;
  106. ypos = y;
  107. }
  108. void CCursorHandler::shiftPos( int &x, int &y )
  109. {
  110. if(( type == Cursor::Type::COMBAT && frame != static_cast<size_t>(Cursor::Combat::POINTER)) || type == Cursor::Type::SPELLBOOK)
  111. {
  112. x-=16;
  113. y-=16;
  114. // Properly align the melee attack cursors.
  115. if (type == Cursor::Type::COMBAT)
  116. {
  117. switch (static_cast<Cursor::Combat>(frame))
  118. {
  119. case Cursor::Combat::HIT_NORTHEAST:
  120. x -= 6;
  121. y += 16;
  122. break;
  123. case Cursor::Combat::HIT_EAST:
  124. x -= 16;
  125. y += 10;
  126. break;
  127. case Cursor::Combat::HIT_SOUTHEAST:
  128. x -= 6;
  129. y -= 6;
  130. break;
  131. case Cursor::Combat::HIT_SOUTHWEST:
  132. x += 16;
  133. y -= 6;
  134. break;
  135. case Cursor::Combat::HIT_WEST:
  136. x += 16;
  137. y += 11;
  138. break;
  139. case Cursor::Combat::HIT_NORTHWEST:
  140. x += 16;
  141. y += 16;
  142. break;
  143. case Cursor::Combat::HIT_NORTH:
  144. x += 9;
  145. y += 16;
  146. break;
  147. case Cursor::Combat::HIT_SOUTH:
  148. x += 9;
  149. y -= 15;
  150. break;
  151. }
  152. }
  153. }
  154. else if(type == Cursor::Type::ADVENTURE)
  155. {
  156. if (frame == 0)
  157. {
  158. //no-op
  159. }
  160. else if(frame == 2)
  161. {
  162. x -= 12;
  163. y -= 10;
  164. }
  165. else if(frame == 3)
  166. {
  167. x -= 12;
  168. y -= 12;
  169. }
  170. else if(frame < 27)
  171. {
  172. int hlpNum = (frame - 4)%6;
  173. if(hlpNum == 0)
  174. {
  175. x -= 15;
  176. y -= 13;
  177. }
  178. else if(hlpNum == 1)
  179. {
  180. x -= 13;
  181. y -= 13;
  182. }
  183. else if(hlpNum == 2)
  184. {
  185. x -= 20;
  186. y -= 20;
  187. }
  188. else if(hlpNum == 3)
  189. {
  190. x -= 13;
  191. y -= 16;
  192. }
  193. else if(hlpNum == 4)
  194. {
  195. x -= 8;
  196. y -= 9;
  197. }
  198. else if(hlpNum == 5)
  199. {
  200. x -= 14;
  201. y -= 16;
  202. }
  203. }
  204. else if(frame == 41)
  205. {
  206. x -= 14;
  207. y -= 16;
  208. }
  209. else if(frame < 31 || frame == 42)
  210. {
  211. x -= 20;
  212. y -= 20;
  213. }
  214. }
  215. }
  216. void CCursorHandler::centerCursor()
  217. {
  218. this->xpos = static_cast<int>((screen->w / 2.) - (currentCursor->pos.w / 2.));
  219. this->ypos = static_cast<int>((screen->h / 2.) - (currentCursor->pos.h / 2.));
  220. SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
  221. CSDL_Ext::warpMouse(this->xpos, this->ypos);
  222. SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
  223. }
  224. void CCursorHandler::render()
  225. {
  226. if(!showing)
  227. return;
  228. if (type == Cursor::Type::SPELLBOOK)
  229. {
  230. static const float frameDisplayDuration = 0.1f;
  231. frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f;
  232. size_t newFrame = frame;
  233. while (frameTime > frameDisplayDuration)
  234. {
  235. frameTime -= frameDisplayDuration;
  236. newFrame++;
  237. }
  238. auto & animation = cursors.at(static_cast<size_t>(type));
  239. while (newFrame > animation->size())
  240. newFrame -= animation->size();
  241. changeGraphic(Cursor::Type::SPELLBOOK, newFrame);
  242. }
  243. //the must update texture in the main (renderer) thread, but changes to cursor type may come from other threads
  244. updateTexture();
  245. int x = xpos;
  246. int y = ypos;
  247. shiftPos(x, y);
  248. if(dndObject)
  249. {
  250. x -= dndObject->pos.w/2;
  251. y -= dndObject->pos.h/2;
  252. }
  253. SDL_Rect destRect;
  254. destRect.x = x;
  255. destRect.y = y;
  256. destRect.w = 40;
  257. destRect.h = 40;
  258. SDL_RenderCopy(mainRenderer, cursorLayer, nullptr, &destRect);
  259. }
  260. void CCursorHandler::updateTexture()
  261. {
  262. if(needUpdate)
  263. {
  264. SDL_UpdateTexture(cursorLayer, nullptr, buffer->pixels, buffer->pitch);
  265. needUpdate = false;
  266. }
  267. }
  268. CCursorHandler::~CCursorHandler()
  269. {
  270. if(buffer)
  271. SDL_FreeSurface(buffer);
  272. if(cursorLayer)
  273. SDL_DestroyTexture(cursorLayer);
  274. }