Images.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. #include "StdInc.h"
  2. #include "Images.h"
  3. #include "MiscWidgets.h"
  4. #include "../gui/CAnimation.h"
  5. #include "../gui/SDL_Pixels.h"
  6. #include "../gui/SDL_Extensions.h"
  7. #include "../gui/CGuiHandler.h"
  8. #include "../gui/CCursorHandler.h"
  9. #include "../battle/CBattleInterface.h"
  10. #include "../battle/CBattleInterfaceClasses.h"
  11. #include "../CBitmapHandler.h"
  12. #include "../Graphics.h"
  13. #include "../CGameInfo.h"
  14. #include "../CPlayerInterface.h"
  15. #include "../CMessage.h"
  16. #include "../CMusicHandler.h"
  17. #include "../windows/CAdvmapInterface.h"
  18. #include "../../CCallback.h"
  19. #include "../../lib/CConfigHandler.h"
  20. #include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
  21. #include "../../lib/CRandomGenerator.h"
  22. /*
  23. * Images.cpp, part of VCMI engine
  24. *
  25. * Authors: listed in file AUTHORS in main folder
  26. *
  27. * License: GNU General Public License v2.0 or later
  28. * Full text of license available in license.txt file, in main folder
  29. *
  30. */
  31. CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
  32. {
  33. init();
  34. bg = BG;
  35. freeSurf = Free;
  36. pos.x += x;
  37. pos.y += y;
  38. pos.w = BG->w;
  39. pos.h = BG->h;
  40. }
  41. CPicture::CPicture( const std::string &bmpname, int x, int y )
  42. {
  43. init();
  44. bg = BitmapHandler::loadBitmap(bmpname);
  45. freeSurf = true;;
  46. pos.x += x;
  47. pos.y += y;
  48. if(bg)
  49. {
  50. pos.w = bg->w;
  51. pos.h = bg->h;
  52. }
  53. else
  54. {
  55. pos.w = pos.h = 0;
  56. }
  57. }
  58. CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/)
  59. {
  60. init();
  61. createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b));
  62. }
  63. CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/)
  64. {
  65. init();
  66. createSimpleRect(r, screenFormat, color);
  67. }
  68. CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/)
  69. {
  70. needRefresh = false;
  71. srcRect = new Rect(SrcRect);
  72. pos.x += x;
  73. pos.y += y;
  74. pos.w = srcRect->w;
  75. pos.h = srcRect->h;
  76. bg = BG;
  77. freeSurf = free;
  78. }
  79. void CPicture::setSurface(SDL_Surface *to)
  80. {
  81. bg = to;
  82. if (srcRect)
  83. {
  84. pos.w = srcRect->w;
  85. pos.h = srcRect->h;
  86. }
  87. else
  88. {
  89. pos.w = bg->w;
  90. pos.h = bg->h;
  91. }
  92. }
  93. CPicture::~CPicture()
  94. {
  95. if(freeSurf)
  96. SDL_FreeSurface(bg);
  97. delete srcRect;
  98. }
  99. void CPicture::init()
  100. {
  101. needRefresh = false;
  102. srcRect = nullptr;
  103. }
  104. void CPicture::show(SDL_Surface * to)
  105. {
  106. if (needRefresh)
  107. showAll(to);
  108. }
  109. void CPicture::showAll(SDL_Surface * to)
  110. {
  111. if(bg)
  112. {
  113. if(srcRect)
  114. {
  115. SDL_Rect srcRectCpy = *srcRect;
  116. SDL_Rect dstRect = srcRectCpy;
  117. dstRect.x = pos.x;
  118. dstRect.y = pos.y;
  119. CSDL_Ext::blitSurface(bg, &srcRectCpy, to, &dstRect);
  120. }
  121. else
  122. blitAt(bg, pos, to);
  123. }
  124. }
  125. void CPicture::convertToScreenBPP()
  126. {
  127. SDL_Surface *hlp = bg;
  128. bg = SDL_ConvertSurface(hlp,screen->format,0);
  129. CSDL_Ext::setDefaultColorKey(bg);
  130. SDL_FreeSurface(hlp);
  131. }
  132. void CPicture::setAlpha(int value)
  133. {
  134. #ifdef VCMI_SDL1
  135. SDL_SetAlpha(bg, SDL_SRCALPHA, value);
  136. #else
  137. SDL_SetSurfaceAlphaMod(bg,value);
  138. #endif // 0
  139. }
  140. void CPicture::scaleTo(Point size)
  141. {
  142. SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y);
  143. if(freeSurf)
  144. SDL_FreeSurface(bg);
  145. setSurface(scaled);
  146. freeSurf = false;
  147. }
  148. void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color)
  149. {
  150. pos += r;
  151. pos.w = r.w;
  152. pos.h = r.h;
  153. if(screenFormat)
  154. bg = CSDL_Ext::newSurface(r.w, r.h);
  155. else
  156. bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0);
  157. SDL_FillRect(bg, nullptr, color);
  158. freeSurf = true;
  159. }
  160. void CPicture::colorizeAndConvert(PlayerColor player)
  161. {
  162. assert(bg);
  163. colorize(player);
  164. convertToScreenBPP();
  165. }
  166. void CPicture::colorize(PlayerColor player)
  167. {
  168. assert(bg);
  169. graphics->blueToPlayersAdv(bg, player);
  170. }
  171. CFilledTexture::CFilledTexture(std::string imageName, Rect position):
  172. CIntObject(0, position.topLeft()),
  173. texture(BitmapHandler::loadBitmap(imageName))
  174. {
  175. pos.w = position.w;
  176. pos.h = position.h;
  177. }
  178. CFilledTexture::~CFilledTexture()
  179. {
  180. SDL_FreeSurface(texture);
  181. }
  182. void CFilledTexture::showAll(SDL_Surface *to)
  183. {
  184. CSDL_Ext::CClipRectGuard guard(to, pos);
  185. CSDL_Ext::fillTexture(to, texture);
  186. }
  187. CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
  188. frame(Frame),
  189. group(Group),
  190. player(-1),
  191. flags(Flags)
  192. {
  193. pos.x += x;
  194. pos.y += y;
  195. anim = new CAnimation(name);
  196. init();
  197. }
  198. CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, ui8 Flags):
  199. anim(Anim),
  200. frame(Frame),
  201. group(Group),
  202. player(-1),
  203. flags(Flags)
  204. {
  205. pos.x += x;
  206. pos.y += y;
  207. init();
  208. }
  209. size_t CAnimImage::size()
  210. {
  211. return anim->size(group);
  212. }
  213. void CAnimImage::init()
  214. {
  215. anim->load(frame, group);
  216. if (flags & CShowableAnim::BASE)
  217. anim->load(0,group);
  218. IImage *img = anim->getImage(frame, group);
  219. if (img)
  220. {
  221. pos.w = img->width();
  222. pos.h = img->height();
  223. }
  224. }
  225. CAnimImage::~CAnimImage()
  226. {
  227. anim->unload(frame, group);
  228. if (flags & CShowableAnim::BASE)
  229. anim->unload(0,group);
  230. delete anim;
  231. }
  232. void CAnimImage::showAll(SDL_Surface * to)
  233. {
  234. IImage *img;
  235. if ( flags & CShowableAnim::BASE && frame != 0)
  236. if ((img = anim->getImage(0, group)))
  237. img->draw(to, pos.x, pos.y);
  238. if ((img = anim->getImage(frame, group)))
  239. img->draw(to, pos.x, pos.y);
  240. }
  241. void CAnimImage::setFrame(size_t Frame, size_t Group)
  242. {
  243. if (frame == Frame && group==Group)
  244. return;
  245. if (anim->size(Group) > Frame)
  246. {
  247. anim->load(Frame, Group);
  248. anim->unload(frame, group);
  249. frame = Frame;
  250. group = Group;
  251. IImage *img = anim->getImage(frame, group);
  252. if (img)
  253. {
  254. if (flags & CShowableAnim::PLAYER_COLORED)
  255. img->playerColored(player);
  256. pos.w = img->width();
  257. pos.h = img->height();
  258. }
  259. }
  260. else
  261. logGlobal->errorStream() << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!";
  262. }
  263. void CAnimImage::playerColored(PlayerColor currPlayer)
  264. {
  265. player = currPlayer;
  266. flags |= CShowableAnim::PLAYER_COLORED;
  267. anim->getImage(frame, group)->playerColored(player);
  268. if (flags & CShowableAnim::BASE)
  269. anim->getImage(0, group)->playerColored(player);
  270. }
  271. CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group):
  272. anim(new CAnimation(name, Flags & USE_RLE)),
  273. group(Group),
  274. frame(0),
  275. first(0),
  276. frameDelay(Delay),
  277. value(0),
  278. flags(Flags),
  279. xOffset(0),
  280. yOffset(0),
  281. alpha(255)
  282. {
  283. anim->loadGroup(group);
  284. last = anim->size(group);
  285. pos.w = anim->getImage(0, group)->width();
  286. pos.h = anim->getImage(0, group)->height();
  287. pos.x+= x;
  288. pos.y+= y;
  289. }
  290. CShowableAnim::~CShowableAnim()
  291. {
  292. anim->unloadGroup(group);
  293. delete anim;
  294. }
  295. void CShowableAnim::setAlpha(ui32 alphaValue)
  296. {
  297. alpha = std::min<ui32>(alphaValue, 255);
  298. }
  299. bool CShowableAnim::set(size_t Group, size_t from, size_t to)
  300. {
  301. size_t max = anim->size(Group);
  302. if (to < max)
  303. max = to;
  304. if (max < from || max == 0)
  305. return false;
  306. anim->load(Group);
  307. anim->unload(group);
  308. group = Group;
  309. frame = first = from;
  310. last = max;
  311. value = 0;
  312. return true;
  313. }
  314. bool CShowableAnim::set(size_t Group)
  315. {
  316. if (anim->size(Group)== 0)
  317. return false;
  318. if (group != Group)
  319. {
  320. anim->loadGroup(Group);
  321. anim->unloadGroup(group);
  322. first = 0;
  323. group = Group;
  324. last = anim->size(Group);
  325. }
  326. frame = value = 0;
  327. return true;
  328. }
  329. void CShowableAnim::reset()
  330. {
  331. value = 0;
  332. frame = first;
  333. if (callback)
  334. callback();
  335. }
  336. void CShowableAnim::clipRect(int posX, int posY, int width, int height)
  337. {
  338. xOffset = posX;
  339. yOffset = posY;
  340. pos.w = width;
  341. pos.h = height;
  342. }
  343. void CShowableAnim::show(SDL_Surface * to)
  344. {
  345. if ( flags & BASE )// && frame != first) // FIXME: results in graphical glytch in Fortress, upgraded hydra's dwelling
  346. blitImage(first, group, to);
  347. blitImage(frame, group, to);
  348. if ((flags & PLAY_ONCE) && frame + 1 == last)
  349. return;
  350. if ( ++value == frameDelay )
  351. {
  352. value = 0;
  353. if ( ++frame >= last)
  354. reset();
  355. }
  356. }
  357. void CShowableAnim::showAll(SDL_Surface * to)
  358. {
  359. if ( flags & BASE )// && frame != first)
  360. blitImage(first, group, to);
  361. blitImage(frame, group, to);
  362. }
  363. void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
  364. {
  365. assert(to);
  366. Rect src( xOffset, yOffset, pos.w, pos.h);
  367. IImage * img = anim->getImage(frame, group);
  368. if (img)
  369. img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
  370. }
  371. void CShowableAnim::rotate(bool on, bool vertical)
  372. {
  373. ui8 flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
  374. if (on)
  375. flags |= flag;
  376. else
  377. flags &= ~flag;
  378. }
  379. CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, ui8 flags, EAnimType type):
  380. CShowableAnim(x,y,name,flags,4,type)
  381. {
  382. xOffset = picPos.x;
  383. yOffset = picPos.y;
  384. if (picPos.w)
  385. pos.w = picPos.w;
  386. if (picPos.h)
  387. pos.h = picPos.h;
  388. };
  389. void CCreatureAnim::loopPreview(bool warMachine)
  390. {
  391. std::vector<EAnimType> available;
  392. static const EAnimType creaPreviewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
  393. static const EAnimType machPreviewList[] = {HOLDING, MOVING, SHOOT_UP, SHOOT_FRONT, SHOOT_DOWN};
  394. auto & previewList = warMachine ? machPreviewList : creaPreviewList;
  395. for (auto & elem : previewList)
  396. if (anim->size(elem))
  397. available.push_back(elem);
  398. size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
  399. if (rnd >= available.size())
  400. {
  401. EAnimType type;
  402. if ( anim->size(MOVING) == 0 )//no moving animation present
  403. type = HOLDING;
  404. else
  405. type = MOVING;
  406. //display this anim for ~1 second (time is random, but it looks good)
  407. for (size_t i=0; i< 12/anim->size(type) + 1; i++)
  408. addLast(type);
  409. }
  410. else
  411. addLast(available[rnd]);
  412. }
  413. void CCreatureAnim::addLast(EAnimType newType)
  414. {
  415. if (type != MOVING && newType == MOVING)//starting moving - play init sequence
  416. {
  417. queue.push( MOVE_START );
  418. }
  419. else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
  420. {
  421. queue.push( MOVE_END );
  422. }
  423. if (newType == TURN_L || newType == TURN_R)
  424. queue.push(newType);
  425. queue.push(newType);
  426. }
  427. void CCreatureAnim::reset()
  428. {
  429. //if we are in the middle of rotation - set flag
  430. if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
  431. rotate(true);
  432. if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
  433. rotate(false);
  434. while (!queue.empty())
  435. {
  436. EAnimType at = queue.front();
  437. queue.pop();
  438. if (set(at))
  439. return;
  440. }
  441. if (callback)
  442. callback();
  443. while (!queue.empty())
  444. {
  445. EAnimType at = queue.front();
  446. queue.pop();
  447. if (set(at))
  448. return;
  449. }
  450. set(HOLDING);
  451. }
  452. void CCreatureAnim::startPreview(bool warMachine)
  453. {
  454. callback = std::bind(&CCreatureAnim::loopPreview, this, warMachine);
  455. }
  456. void CCreatureAnim::clearAndSet(EAnimType type)
  457. {
  458. while (!queue.empty())
  459. queue.pop();
  460. set(type);
  461. }