CAnimation.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. #include <iostream>
  2. #include <sstream>
  3. #include <boost/foreach.hpp>
  4. #include <boost/bind.hpp>
  5. #include "SDL.h"
  6. #include "SDL_image.h"
  7. #include "CBitmapHandler.h"
  8. #include "CAnimation.h"
  9. #include "SDL_Extensions.h"
  10. #include "../hch/CLodHandler.h"
  11. /*
  12. * CAnimation.cpp, part of VCMI engine
  13. *
  14. * Authors: listed in file AUTHORS in main folder
  15. *
  16. * License: GNU General Public License v2.0 or later
  17. * Full text of license available in license.txt file, in main folder
  18. *
  19. */
  20. extern DLL_EXPORT CLodHandler *spriteh;
  21. /*************************************************************************
  22. * DefFile, class used for def loading *
  23. *************************************************************************/
  24. bool CDefFile::haveFrame(size_t frame, size_t group) const
  25. {
  26. if (offset.size() > group)
  27. if (offset[group].size() > frame)
  28. return true;
  29. return false;
  30. }
  31. SDL_Surface * CDefFile::loadFrame(size_t frame, size_t group) const
  32. {
  33. if (haveFrame(frame, group))
  34. return loadFrame(( unsigned char * )data+offset[group][frame], colors);
  35. return NULL;
  36. }
  37. SDL_Surface * CDefFile::loadFrame (const unsigned char * FDef, const BMPPalette * palette)
  38. {
  39. SDL_Surface * ret=NULL;
  40. unsigned int BaseOffset,
  41. SpriteWidth, SpriteHeight, //format of sprite
  42. TotalRowLength, // length of read segment
  43. add, FullHeight,FullWidth,
  44. RowAdd,
  45. prSize,
  46. defType2;
  47. int LeftMargin, RightMargin, TopMargin, BottomMargin;
  48. unsigned char SegmentType;
  49. BaseOffset = 0;
  50. SSpriteDef sd = * reinterpret_cast<const SSpriteDef *>(FDef + BaseOffset);
  51. prSize = SDL_SwapLE32(sd.prSize);
  52. defType2 = SDL_SwapLE32(sd.defType2);
  53. FullWidth = SDL_SwapLE32(sd.FullWidth);
  54. FullHeight = SDL_SwapLE32(sd.FullHeight);
  55. SpriteWidth = SDL_SwapLE32(sd.SpriteWidth);
  56. SpriteHeight = SDL_SwapLE32(sd.SpriteHeight);
  57. LeftMargin = SDL_SwapLE32(sd.LeftMargin);
  58. TopMargin = SDL_SwapLE32(sd.TopMargin);
  59. RightMargin = FullWidth - SpriteWidth - LeftMargin;
  60. BottomMargin = FullHeight - SpriteHeight - TopMargin;
  61. //if(LeftMargin + RightMargin < 0)
  62. // SpriteWidth += LeftMargin + RightMargin; //ugly construction... TODO: check how to do it nicer
  63. if (LeftMargin<0)
  64. SpriteWidth+=LeftMargin;
  65. if (RightMargin<0)
  66. SpriteWidth+=RightMargin;
  67. // Note: this looks bogus because we allocate only FullWidth, not FullWidth+add
  68. add = 4 - FullWidth%4;
  69. if (add==4)
  70. add=0;
  71. ret = SDL_CreateRGBSurface(SDL_SWSURFACE, FullWidth, FullHeight, 8, 0, 0, 0, 0);
  72. //int tempee2 = readNormalNr(0,4,((unsigned char *)tempee.c_str()));
  73. BaseOffset += sizeof(SSpriteDef);
  74. int BaseOffsetor = BaseOffset;
  75. for (int i=0; i<256; ++i)
  76. {
  77. SDL_Color pr;
  78. pr.r = palette[i].R;
  79. pr.g = palette[i].G;
  80. pr.b = palette[i].B;
  81. pr.unused = palette[i].F;
  82. (*(ret->format->palette->colors+i))=pr;
  83. }
  84. int ftcp=0;
  85. // If there's a margin anywhere, just blank out the whole surface.
  86. if (TopMargin > 0 || BottomMargin > 0 || LeftMargin > 0 || RightMargin > 0)
  87. {
  88. memset( reinterpret_cast<char*>(ret->pixels), 0, FullHeight*FullWidth);
  89. }
  90. // Skip top margin
  91. if (TopMargin > 0)
  92. ftcp += TopMargin*(FullWidth+add);
  93. switch (defType2)
  94. {
  95. case 0:
  96. {
  97. for (unsigned int i=0; i<SpriteHeight; i++)
  98. {
  99. if (LeftMargin>0)
  100. ftcp += LeftMargin;
  101. memcpy(reinterpret_cast<char*>(ret->pixels)+ftcp, &FDef[BaseOffset], SpriteWidth);
  102. ftcp += SpriteWidth;
  103. BaseOffset += SpriteWidth;
  104. if (RightMargin>0)
  105. ftcp += RightMargin;
  106. }
  107. }
  108. break;
  109. case 1:
  110. {
  111. const unsigned int * RWEntriesLoc = reinterpret_cast<const unsigned int *>(FDef+BaseOffset);
  112. BaseOffset += sizeof(int) * SpriteHeight;
  113. for (unsigned int i=0; i<SpriteHeight; i++)
  114. {
  115. BaseOffset=BaseOffsetor + SDL_SwapLE32(read_unaligned_u32(RWEntriesLoc + i));
  116. if (LeftMargin>0)
  117. ftcp += LeftMargin;
  118. TotalRowLength=0;
  119. do
  120. {
  121. unsigned int SegmentLength;
  122. SegmentType=FDef[BaseOffset++];
  123. SegmentLength=FDef[BaseOffset++] + 1;
  124. if (SegmentType==0xFF)
  125. {
  126. memcpy(reinterpret_cast<char*>(ret->pixels)+ftcp, FDef + BaseOffset, SegmentLength);
  127. BaseOffset+=SegmentLength;
  128. }
  129. else
  130. {
  131. memset(reinterpret_cast<char*>(ret->pixels)+ftcp, SegmentType, SegmentLength);
  132. }
  133. ftcp += SegmentLength;
  134. TotalRowLength += SegmentLength;
  135. }
  136. while (TotalRowLength<SpriteWidth);
  137. RowAdd=SpriteWidth-TotalRowLength;
  138. if (RightMargin>0)
  139. ftcp += RightMargin;
  140. if (add>0)
  141. ftcp += add+RowAdd;
  142. }
  143. }
  144. break;
  145. case 2:
  146. {
  147. BaseOffset = BaseOffsetor + SDL_SwapLE16(read_unaligned_u16(FDef + BaseOffsetor));
  148. for (unsigned int i=0; i<SpriteHeight; i++)
  149. {
  150. //BaseOffset = BaseOffsetor+RWEntries[i];
  151. if (LeftMargin>0)
  152. ftcp += LeftMargin;
  153. TotalRowLength=0;
  154. do
  155. {
  156. SegmentType=FDef[BaseOffset++];
  157. unsigned char code = SegmentType / 32;
  158. unsigned char value = (SegmentType & 31) + 1;
  159. if (code==7)
  160. {
  161. memcpy(reinterpret_cast<char*>(ret->pixels)+ftcp, &FDef[BaseOffset], value);
  162. ftcp += value;
  163. BaseOffset += value;
  164. }
  165. else
  166. {
  167. memset(reinterpret_cast<char*>(ret->pixels)+ftcp, code, value);
  168. ftcp += value;
  169. }
  170. TotalRowLength+=value;
  171. }
  172. while (TotalRowLength<SpriteWidth);
  173. if (RightMargin>0)
  174. ftcp += RightMargin;
  175. RowAdd=SpriteWidth-TotalRowLength;
  176. if (add>0)
  177. ftcp += add+RowAdd;
  178. }
  179. }
  180. break;
  181. case 3:
  182. {
  183. for (unsigned int i=0; i<SpriteHeight; i++)
  184. {
  185. BaseOffset = BaseOffsetor + SDL_SwapLE16(read_unaligned_u16(FDef + BaseOffsetor+i*2*(SpriteWidth/32)));
  186. if (LeftMargin>0)
  187. ftcp += LeftMargin;
  188. TotalRowLength=0;
  189. do
  190. {
  191. SegmentType=FDef[BaseOffset++];
  192. unsigned char code = SegmentType / 32;
  193. unsigned char value = (SegmentType & 31) + 1;
  194. int len = std::min<unsigned int>(value, SpriteWidth - TotalRowLength) - std::max(0, -LeftMargin);
  195. amax(len, 0);
  196. if (code==7)
  197. {
  198. memcpy((ui8*)ret->pixels + ftcp, FDef + BaseOffset, len);
  199. ftcp += len;
  200. BaseOffset += len;
  201. }
  202. else
  203. {
  204. memset((ui8*)ret->pixels + ftcp, code, len);
  205. ftcp += len;
  206. }
  207. TotalRowLength+=( LeftMargin>=0 ? value : value+LeftMargin );
  208. }
  209. while (TotalRowLength<SpriteWidth);
  210. if (RightMargin>0)
  211. ftcp += RightMargin;
  212. RowAdd=SpriteWidth-TotalRowLength;
  213. if (add>0)
  214. ftcp += add+RowAdd;
  215. }
  216. }
  217. break;
  218. default:
  219. throw std::string("Unknown sprite format.");
  220. break;
  221. }
  222. SDL_Color *col = ret->format->palette->colors;
  223. Uint32 keycol = SDL_MapRGBA(ret->format, col[0].r, col[0].b, col[0].g, col[0].unused);
  224. SDL_SetColorKey(ret, SDL_SRCCOLORKEY, keycol);
  225. return ret;
  226. };
  227. BMPPalette * CDefFile::getPalette()
  228. {
  229. BMPPalette * ret = new BMPPalette[256];
  230. memcpy(ret, colors, sizeof(BMPPalette)*256);
  231. return ret;
  232. }
  233. CDefFile::CDefFile(std::string Name):data(NULL),colors(NULL)
  234. {
  235. static SDL_Color H3Palette[8] = {{ 0, 0, 0, 255},
  236. { 0, 0, 0, 192},
  237. { 0, 0, 0, 128},
  238. { 0, 0, 0, 64},
  239. { 0, 0, 0, 32},
  240. {255, 255, 0, 255},
  241. {255, 255, 0, 255},
  242. {255, 255, 0, 255}};//H3 palette for shadow\selection highlight
  243. data = spriteh->giveFile(Name, FILE_ANIMATION, &datasize);
  244. if (!data)
  245. {
  246. tlog0<<"Error: file "<< Name <<" not found\n";
  247. return;
  248. }
  249. colors = new BMPPalette[256];
  250. int it = 0;
  251. type = readNormalNr(data, it); it+=4;
  252. //int width = readNormalNr(data, it); it+=4;//not used
  253. //int height = readNormalNr(data, it); it+=4;
  254. it+=8;
  255. unsigned int totalBlocks = readNormalNr(data, it);
  256. it+=4;
  257. for (unsigned int i= 0; i<256; i++)
  258. {
  259. colors[i].R = data[it++];
  260. colors[i].G = data[it++];
  261. colors[i].B = data[it++];
  262. colors[i].F = 0;
  263. }
  264. memcpy(colors, H3Palette, (type == 66)? 32:20);//initialize shadow\selection colors
  265. offList.insert(datasize);
  266. for (unsigned int i=0; i<totalBlocks; i++)
  267. {
  268. unsigned int blockID = readNormalNr(data, it);
  269. it+=4;
  270. unsigned int totalEntries = readNormalNr(data, it);
  271. it+=12;
  272. //8 unknown bytes - skipping
  273. //13 bytes for name of every frame in this block - not used, skipping
  274. it+= 13 * totalEntries;
  275. offset.resize(std::max(blockID+1, offset.size()));
  276. for (unsigned int j=0; j<totalEntries; j++)
  277. {
  278. size_t currOffset = readNormalNr(data, it);
  279. offset[blockID].push_back(currOffset);
  280. offList.insert(currOffset);
  281. it += 4;
  282. }
  283. }
  284. }
  285. unsigned char * CDefFile::getFrame(size_t frame, size_t group) const
  286. {
  287. if (offset.size() > group)
  288. {
  289. if (offset[group].size() > frame)
  290. {
  291. size_t offs = offset[group][frame];
  292. std::set<size_t>::iterator it = offList.find(offs);
  293. if (it == offList.end() || ++it == offList.end())
  294. tlog0<<"Error: offset not found!\n";
  295. size_t size = *it - offs;
  296. unsigned char * ret = new unsigned char[size];
  297. memcpy(ret, data+offs, size);
  298. return ret;
  299. }
  300. }
  301. return NULL;
  302. }
  303. CDefFile::~CDefFile()
  304. {
  305. offset.clear();
  306. offList.clear();
  307. delete[] data;
  308. delete[] colors;
  309. }
  310. bool CDefFile::loaded() const
  311. {
  312. return data != NULL;
  313. }
  314. /*************************************************************************
  315. * CAnimation for animations handling, can load part of file if needed *
  316. *************************************************************************/
  317. CAnimation::AnimEntry::AnimEntry():
  318. surf(NULL),
  319. source(0),
  320. refCount(0),
  321. data(NULL),
  322. dataSize(0)
  323. {
  324. }
  325. bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
  326. {
  327. if (groupSize(group) <= frame)
  328. {
  329. printError(frame, group, "LoadFrame");
  330. return false;
  331. }
  332. AnimEntry &e = entries[group][frame];
  333. if (e.surf || e.data)
  334. {
  335. e.refCount++;
  336. return true;
  337. }
  338. if (e.source & 6)//load frame with SDL_Image
  339. {
  340. int size;
  341. unsigned char * pic = NULL;
  342. std::ostringstream str;
  343. if ( e.source & 2 )
  344. str << name << '#' << (group+1) << '#' << (frame+1); // file#12#34.*
  345. else
  346. str << name << '#' << (frame+1);//file#34.*
  347. pic = spriteh->giveFile(str.str(), FILE_GRAPHICS, &size);
  348. if (pic)
  349. {
  350. if (compressed)
  351. {
  352. e.data = pic;
  353. e.dataSize = size;
  354. }
  355. else
  356. {
  357. e.surf = IMG_Load_RW( SDL_RWFromMem((void*)pic, size), 1);
  358. delete [] pic;
  359. }
  360. }
  361. }
  362. else if (file && e.source & 1)//try to get image from def
  363. {
  364. if (compressed)
  365. e.data = file->getFrame(frame, group);
  366. else
  367. e.surf = file->loadFrame(frame, group);
  368. }
  369. if (!(e.surf || e.data))
  370. return false;//failed to load
  371. e.refCount++;
  372. return true;
  373. }
  374. bool CAnimation::unloadFrame(size_t frame, size_t group)
  375. {
  376. if (groupSize(group) > frame && entries[group][frame].refCount)
  377. {
  378. AnimEntry &e = entries[group][frame];
  379. if (--e.refCount)//not last ref
  380. return true;
  381. SDL_FreeSurface(e.surf);
  382. delete [] e.data;
  383. e.surf = NULL;
  384. e.data = NULL;
  385. return true;
  386. }
  387. return false;
  388. }
  389. void CAnimation::decompress(AnimEntry &entry)
  390. {
  391. if (entry.source & 6)//load frame with SDL_Image
  392. entry.surf = IMG_Load_RW( SDL_RWFromMem((void*)entry.data, entry.dataSize), 1);
  393. else if (entry.source & 1)
  394. entry.surf = CDefFile::loadFrame(entry.data, defPalette);
  395. }
  396. void CAnimation::init(CDefFile * file)
  397. {
  398. if (compressed)
  399. defPalette = file->getPalette();
  400. for (size_t group = 0; ; group++)
  401. {
  402. std::vector<AnimEntry> toAdd;
  403. for (size_t frame = 0; ; frame++)
  404. {
  405. unsigned char res=0;
  406. {
  407. std::ostringstream str;
  408. str << name << '#' << (group+1) << '#' << (frame+1); // format: file#12#34.*
  409. if (spriteh->haveFile(str.str()))
  410. res |= 2;
  411. }
  412. if (group == 0)
  413. {
  414. std::ostringstream str;
  415. str << name << '#' << (frame+1);// format: file#34.*
  416. if ( spriteh->haveFile(str.str()))
  417. res |=4;
  418. }
  419. if (file)//we have def too. try to get image from def
  420. {
  421. if (file->haveFrame(frame, group))
  422. res |=1;
  423. }
  424. if (res)
  425. {
  426. toAdd.push_back(AnimEntry());
  427. toAdd.back().source = res;
  428. }
  429. else
  430. break;
  431. }
  432. if (!toAdd.empty())
  433. {
  434. entries.push_back(toAdd);
  435. }
  436. else
  437. {
  438. entries.resize(entries.size()+1);
  439. if (group > 21)
  440. break;//FIXME: crude workaround: if some groups are not present
  441. //(common for creatures) parser will exit before reaching them
  442. }
  443. }
  444. }
  445. CDefFile * CAnimation::getFile() const
  446. {
  447. CDefFile * file = new CDefFile(name);
  448. if (!file->loaded())
  449. {
  450. delete file;
  451. return NULL;
  452. }
  453. return file;
  454. }
  455. void CAnimation::printError(size_t frame, size_t group, std::string type) const
  456. {
  457. tlog0 << type <<" error: Request for frame not present in CAnimation!\n"
  458. <<"\tFile name: "<<name<<" Group: "<<group<<" Frame: "<<frame<<"\n";
  459. }
  460. CAnimation::CAnimation(std::string Name, bool Compressed):
  461. name(Name),
  462. compressed(Compressed),
  463. defPalette(NULL)
  464. {
  465. std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper);
  466. int dotPos = name.find_last_of('.');
  467. if ( dotPos != -1 )
  468. name.erase(dotPos);
  469. CDefFile * file = getFile();
  470. init(file);
  471. delete file;
  472. }
  473. CAnimation::CAnimation():
  474. name(""),
  475. compressed(false),
  476. defPalette(NULL)
  477. {
  478. }
  479. CAnimation::~CAnimation()
  480. {
  481. delete [] defPalette;
  482. for (size_t i = 0; i < entries.size(); i++)
  483. for (size_t j = 0; j < entries.at(i).size(); j++)
  484. {
  485. delete [] entries[i][j].data;
  486. if (entries[i][j].surf)
  487. SDL_FreeSurface(entries[i][j].surf);
  488. }
  489. }
  490. void CAnimation::add(SDL_Surface * surf, bool shared, size_t group)
  491. {
  492. if (!surf)
  493. return;
  494. if (entries.size() <= group)
  495. entries.resize(group+1);
  496. if (shared)
  497. surf->refcount++;
  498. entries[group].push_back(AnimEntry());
  499. entries[group].back().refCount = 1;
  500. entries[group].back().surf = surf;
  501. }
  502. void CAnimation::removeDecompressed(size_t frame, size_t group)
  503. {
  504. AnimEntry &e = entries[group][frame];
  505. if (e.surf && e.data)
  506. {
  507. SDL_FreeSurface(e.surf);
  508. e.surf = NULL;
  509. }
  510. }
  511. SDL_Surface * CAnimation::image(size_t frame)
  512. {
  513. size_t group=0;
  514. while (group<entries.size() && frame > entries[group].size())
  515. frame -= entries[group].size();
  516. if (group <entries.size() && frame < entries[group].size())
  517. return image(frame, group);
  518. return NULL;
  519. }
  520. SDL_Surface * CAnimation::image(size_t frame, size_t group)
  521. {
  522. if ( groupSize(group) > frame )
  523. {
  524. AnimEntry &e = entries[group][frame];
  525. if (!e.surf && e.data)
  526. decompress(e);
  527. return e.surf;
  528. }
  529. printError(frame, group, "GetImage");
  530. return NULL;
  531. }
  532. void CAnimation::clear()
  533. {
  534. unload();
  535. entries.clear();
  536. }
  537. void CAnimation::load()
  538. {
  539. CDefFile * file = getFile();
  540. for (size_t group = 0; group<entries.size(); group++)
  541. for (size_t frame = 0; frame<entries[group].size(); frame++)
  542. loadFrame(file, frame, group);
  543. delete file;
  544. }
  545. void CAnimation::unload()
  546. {
  547. for (size_t group = 0; group<entries.size(); group++)
  548. for (size_t frame = 0; frame<entries[group].size(); frame++)
  549. unloadFrame(frame, group);
  550. }
  551. void CAnimation::loadGroup(size_t group)
  552. {
  553. CDefFile * file = getFile();
  554. for (size_t frame = 0; frame<groupSize(group); frame++)
  555. loadFrame(file, frame, group);
  556. delete file;
  557. }
  558. void CAnimation::unloadGroup(size_t group)
  559. {
  560. for (size_t frame = 0; frame<groupSize(group); frame++)
  561. unloadFrame(frame, group);
  562. }
  563. void CAnimation::load(size_t frame, size_t group)
  564. {
  565. CDefFile * file = getFile();
  566. loadFrame(file, frame, group);
  567. delete file;
  568. }
  569. void CAnimation::unload(size_t frame, size_t group)
  570. {
  571. unloadFrame(frame, group);
  572. }
  573. void CAnimation::load(std::vector <std::pair <size_t, size_t> > frames)
  574. {
  575. CDefFile * file = getFile();
  576. for (size_t i=0; i<frames.size(); i++)
  577. loadFrame(file, frames[i].second, frames[i].first);
  578. delete file;
  579. }
  580. void CAnimation::unload(std::vector <std::pair <size_t, size_t> > frames)
  581. {
  582. for (size_t i=0; i<frames.size(); i++)
  583. unloadFrame(frames[i].second, frames[i].first);
  584. }
  585. void CAnimation::fixButtonPos()
  586. {
  587. if ( groupSize(0) > 1 )
  588. std::swap(entries[0][1].surf, entries[0][0].surf);
  589. }
  590. size_t CAnimation::groupSize(size_t group) const
  591. {
  592. if (entries.size() > group)
  593. return entries[group].size();
  594. return 0;
  595. }
  596. size_t CAnimation::size() const
  597. {
  598. size_t ret=0;
  599. for (size_t i=0; i<entries.size(); i++)
  600. {
  601. ret += entries[i].size();
  602. }
  603. return ret;
  604. }
  605. /*
  606. CAnimImage::CAnimImage(int x, int y, std::string name, size_t Frame, size_t Group):
  607. anim(name),
  608. frame(Frame),
  609. group(Group)
  610. {
  611. anim.load(frame, group);
  612. pos.w = anim.image(frame, group)->w;
  613. pos.h = anim.image(frame, group)->h;
  614. }
  615. CAnimImage::~CAnimImage()
  616. {
  617. }
  618. void CAnimImage::show(SDL_Surface *to)
  619. {
  620. blitAtLoc(anim.image(frame, group), 0,0, to);
  621. }
  622. void CAnimImage::setFrame(size_t Frame, size_t Group)
  623. {
  624. if (frame == Frame && group==Group)
  625. return;
  626. if (anim.groupSize(Group) > Frame)
  627. {
  628. anim.unload(frame, group);
  629. anim.load(Frame, Group);
  630. frame = Frame;
  631. group = Group;
  632. }
  633. }
  634. */
  635. CShowableAnim::CShowableAnim(int x, int y, std::string name, unsigned char Flags, unsigned int Delay, size_t Group):
  636. anim(name, Flags),
  637. group(Group),
  638. frame(0),
  639. first(0),
  640. flags(Flags),
  641. frameDelay(Delay),
  642. value(0),
  643. xOffset(0),
  644. yOffset(0)
  645. {
  646. pos.x+=x;
  647. pos.y+=y;
  648. anim.loadGroup(group);
  649. last = anim.groupSize(group);
  650. pos.w = anim.image(0, group)->w;
  651. pos.h = anim.image(0, group)->h;
  652. }
  653. CShowableAnim::~CShowableAnim()
  654. {
  655. }
  656. bool CShowableAnim::set(size_t Group, size_t from, size_t to)
  657. {
  658. size_t max = anim.groupSize(Group);
  659. if (max>to)
  660. max = to;
  661. if (max < from || max == 0)
  662. return false;
  663. anim.load(Group);
  664. anim.unload(group);
  665. group = Group;
  666. frame = first = from;
  667. last = max;
  668. value = 0;
  669. return true;
  670. }
  671. bool CShowableAnim::set(size_t Group)
  672. {
  673. if (anim.groupSize(Group)== 0)
  674. return false;
  675. if (group != Group)
  676. {
  677. anim.loadGroup(Group);
  678. anim.unloadGroup(group);
  679. first = 0;
  680. group = Group;
  681. last = anim.groupSize(Group);
  682. }
  683. frame = value = 0;
  684. return true;
  685. }
  686. void CShowableAnim::reset()
  687. {
  688. value = 0;
  689. frame = first;
  690. if (callback)
  691. callback();
  692. }
  693. void CShowableAnim::movePic( int byX, int byY)
  694. {
  695. xOffset += byX;
  696. yOffset += byY;
  697. }
  698. void CShowableAnim::show(SDL_Surface *to)
  699. {
  700. if ( flags & FLAG_BASE && frame != first)
  701. blitImage(anim.image(first, group), to);
  702. blitImage(anim.image(frame, group), to);
  703. if ( ++value == frameDelay )
  704. {
  705. value = 0;
  706. if (flags & FLAG_COMPRESSED)
  707. anim.removeDecompressed(frame, group);
  708. if ( ++frame == last)
  709. reset();
  710. }
  711. }
  712. void CShowableAnim::showAll(SDL_Surface *to)
  713. {
  714. show(to);
  715. }
  716. void CShowableAnim::blitImage(SDL_Surface *what, SDL_Surface *to)
  717. {
  718. assert(what);
  719. //TODO: SDL RLE?
  720. SDL_Rect dstRect=genRect(pos.h, pos.w, pos.x, pos.y);
  721. SDL_Rect srcRect;
  722. srcRect.x = xOffset;
  723. srcRect.y = yOffset;
  724. srcRect.w = pos.w;
  725. srcRect.h = pos.h;
  726. /*if ( flags & FLAG_ROTATED )
  727. {} //TODO: rotate surface
  728. else */
  729. if (flags & FLAG_ALPHA && what->format->BytesPerPixel == 1) //alpha on 8-bit surf - use custom blitter
  730. CSDL_Ext::blit8bppAlphaTo24bpp(what, &srcRect, to, &dstRect);
  731. else
  732. CSDL_Ext::blitSurface(what, &srcRect, to, &dstRect);
  733. }
  734. void CShowableAnim::rotate(bool on)
  735. {
  736. if (on)
  737. flags |= FLAG_ROTATED;
  738. else
  739. flags &= ~FLAG_ROTATED;
  740. }
  741. CCreatureAnim::CCreatureAnim(int x, int y, std::string name, unsigned char flags, EAnimType type):
  742. CShowableAnim(x,y,name,flags,3,type)
  743. {
  744. if (flags & FLAG_PREVIEW)
  745. callback = boost::bind(&CCreatureAnim::loopPreview,this);
  746. };
  747. void CCreatureAnim::loopPreview()
  748. {
  749. std::vector<EAnimType> available;
  750. if (anim.groupSize(ANIM_HOLDING))
  751. available.push_back(ANIM_HOLDING);
  752. if (anim.groupSize(ANIM_HITTED))
  753. available.push_back(ANIM_HITTED);
  754. if (anim.groupSize(ANIM_DEFENCE))
  755. available.push_back(ANIM_DEFENCE);
  756. if (anim.groupSize(ANIM_ATTACK_FRONT))
  757. available.push_back(ANIM_ATTACK_FRONT);
  758. if (anim.groupSize(ANIM_CAST_FRONT))
  759. available.push_back(ANIM_CAST_FRONT);
  760. size_t rnd = rand()%(available.size()*2);
  761. if (rnd >= available.size())
  762. {
  763. if ( anim.groupSize(ANIM_MOVING) == 0 )//no moving animation present
  764. addLast( ANIM_HOLDING );
  765. else
  766. addLast( ANIM_MOVING ) ;
  767. }
  768. else
  769. addLast(available[rnd]);
  770. }
  771. void CCreatureAnim::addLast(EAnimType newType)
  772. {
  773. if (type != ANIM_MOVING && newType == ANIM_MOVING)//starting moving - play init sequence
  774. {
  775. queue.push( ANIM_MOVE_START );
  776. }
  777. else if (type == ANIM_MOVING && newType != ANIM_MOVING )//previous anim was moving - finish it
  778. {
  779. queue.push( ANIM_MOVE_END);
  780. }
  781. if (newType == ANIM_TURN_L || newType == ANIM_TURN_R)
  782. queue.push(newType);
  783. queue.push(newType);
  784. }
  785. void CCreatureAnim::reset()
  786. {
  787. //if we are in the middle of rotation - set flag
  788. if (type == ANIM_TURN_L && !queue.empty() && queue.front() == ANIM_TURN_L)
  789. flags |= FLAG_ROTATED;
  790. if (type == ANIM_TURN_R && !queue.empty() && queue.front() == ANIM_TURN_R)
  791. flags &= ~FLAG_ROTATED;
  792. while (!queue.empty())//FIXME: remove dublication
  793. {
  794. EAnimType at = queue.front();
  795. queue.pop();
  796. if (set(at))
  797. return;
  798. }
  799. if (callback)
  800. callback();
  801. while (!queue.empty())
  802. {
  803. EAnimType at = queue.front();
  804. queue.pop();
  805. if (set(at))
  806. return;
  807. }
  808. tlog0<<"Warning: next sequence is not found for animation!\n";
  809. }
  810. void CCreatureAnim::clearAndSet(EAnimType type)
  811. {
  812. while (!queue.empty())
  813. queue.pop();
  814. set(type);
  815. }