CAnimation.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287
  1. #include <boost/bind.hpp>
  2. #include <boost/algorithm/string/trim.hpp>
  3. #include "SDL_image.h"
  4. #include "../lib/CLodHandler.h"
  5. #include "CBitmapHandler.h"
  6. #include "Graphics.h"
  7. #include "CAnimation.h"
  8. #include "SDL_Extensions.h"
  9. /*
  10. * CAnimation.cpp, part of VCMI engine
  11. *
  12. * Authors: listed in file AUTHORS in main folder
  13. *
  14. * License: GNU General Public License v2.0 or later
  15. * Full text of license available in license.txt file, in main folder
  16. *
  17. */
  18. extern DLL_EXPORT CLodHandler *spriteh;
  19. typedef std::map <size_t, std::vector <std::string> > source_map;
  20. typedef std::map<size_t, IImage* > image_map;
  21. typedef std::map<size_t, image_map > group_map;
  22. class SDLImageLoader
  23. {
  24. SDLImage * image;
  25. ui8 * lineStart;
  26. ui8 * position;
  27. public:
  28. //load size raw pixels from data
  29. inline void Load(size_t size, const ui8 * data);
  30. //set size pixels to color
  31. inline void Load(size_t size, ui8 color=0);
  32. inline void EndLine();
  33. //init image with these sizes and palette
  34. inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal);
  35. SDLImageLoader(SDLImage * Img);
  36. ~SDLImageLoader();
  37. };
  38. class CompImageLoader
  39. {
  40. CompImage * image;
  41. ui8 *position;
  42. ui8 *entry;
  43. unsigned int currentLine;
  44. inline ui8 typeOf(ui8 color);
  45. inline void NewEntry(ui8 color, size_t size);
  46. inline void NewEntry(const ui8 * &data, size_t size);
  47. public:
  48. //load size raw pixels from data
  49. inline void Load(size_t size, const ui8 * data);
  50. //set size pixels to color
  51. inline void Load(size_t size, ui8 color=0);
  52. inline void EndLine();
  53. //init image with these sizes and palette
  54. inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal);
  55. CompImageLoader(CompImage * Img);
  56. ~CompImageLoader();
  57. };
  58. //Small internal class for parsing texts
  59. class TextParser
  60. {
  61. int type;
  62. size_t position;
  63. std::string text;
  64. public:
  65. TextParser(const std::string &name);
  66. int getType() const;
  67. void parseFile(std::map<size_t, std::vector <std::string> > &result);
  68. };
  69. /*************************************************************************
  70. * DefFile, class used for def loading *
  71. *************************************************************************/
  72. size_t getPaletteSize(int type)
  73. {
  74. switch (type)
  75. {
  76. case 66: return 32;
  77. case 71: return 4;
  78. default: return 20;
  79. }
  80. }
  81. CDefFile::CDefFile(std::string Name):
  82. data(NULL),
  83. palette(NULL)
  84. {
  85. //First 8 colors in def palette used for transparency
  86. static SDL_Color H3Palette[8] =
  87. {
  88. { 0, 0, 0, 0},// 100% - transparency
  89. { 0, 0, 0, 192},// 75% - shadow border,
  90. { 0, 0, 0, 128},// TODO: find exact value
  91. { 0, 0, 0, 128},// TODO: for transparency
  92. { 0, 0, 0, 128},// 50% - shadow body
  93. { 0, 0, 0, 0},// 100% - selection highlight
  94. { 0, 0, 0, 128},// 50% - shadow body below selection
  95. { 0, 0, 0, 192} // 75% - shadow border below selection
  96. };
  97. data = spriteh->giveFile(Name, FILE_ANIMATION);
  98. palette = new SDL_Color[256];
  99. int it = 0;
  100. unsigned int type = readNormalNr(data, it);
  101. it+=4;
  102. //int width = readNormalNr(data, it); it+=4;//not used
  103. //int height = readNormalNr(data, it); it+=4;
  104. it+=8;
  105. unsigned int totalBlocks = readNormalNr(data, it);
  106. it+=4;
  107. for (unsigned int i= 0; i<256; i++)
  108. {
  109. palette[i].r = data[it++];
  110. palette[i].g = data[it++];
  111. palette[i].b = data[it++];
  112. palette[i].unused = 255;
  113. }
  114. memcpy(palette, H3Palette, getPaletteSize(type));//initialize shadow\selection colors
  115. for (unsigned int i=0; i<totalBlocks; i++)
  116. {
  117. size_t blockID = readNormalNr(data, it);
  118. it+=4;
  119. size_t totalEntries = readNormalNr(data, it);
  120. it+=12;
  121. //8 unknown bytes - skipping
  122. //13 bytes for name of every frame in this block - not used, skipping
  123. it+= 13 * totalEntries;
  124. for (unsigned int j=0; j<totalEntries; j++)
  125. {
  126. size_t currOffset = readNormalNr(data, it);
  127. offset[blockID].push_back(currOffset);
  128. it += 4;
  129. }
  130. }
  131. }
  132. template<class ImageLoader>
  133. void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const
  134. {
  135. std::map<size_t, std::vector <size_t> >::const_iterator it;
  136. it = offset.find(group);
  137. assert (it != offset.end());
  138. const ui8 * FDef = data+it->second[frame];
  139. const SSpriteDef sd = * reinterpret_cast<const SSpriteDef *>(FDef);
  140. SSpriteDef sprite;
  141. //sprite.size = SDL_SwapLE32(sd.size);//unused
  142. sprite.format = SDL_SwapLE32(sd.format);
  143. sprite.fullWidth = SDL_SwapLE32(sd.fullWidth);
  144. sprite.fullHeight = SDL_SwapLE32(sd.fullHeight);
  145. sprite.width = SDL_SwapLE32(sd.width);
  146. sprite.height = SDL_SwapLE32(sd.height);
  147. sprite.leftMargin = SDL_SwapLE32(sd.leftMargin);
  148. sprite.topMargin = SDL_SwapLE32(sd.topMargin);
  149. unsigned int currentOffset = sizeof(SSpriteDef);
  150. unsigned int BaseOffset = sizeof(SSpriteDef);
  151. loader.init(Point(sprite.width, sprite.height),
  152. Point(sprite.leftMargin, sprite.topMargin),
  153. Point(sprite.fullWidth, sprite.fullHeight), palette);
  154. switch (sprite.format)
  155. {
  156. case 0:
  157. {
  158. //pixel data is not compressed, copy data to surface
  159. for (unsigned int i=0; i<sprite.height; i++)
  160. {
  161. loader.Load(sprite.width, FDef[currentOffset]);
  162. currentOffset += sprite.width;
  163. loader.EndLine();
  164. }
  165. break;
  166. }
  167. case 1:
  168. {
  169. //for each line we have offset of pixel data
  170. const ui32 * RWEntriesLoc = reinterpret_cast<const ui32 *>(FDef+currentOffset);
  171. currentOffset += sizeof(ui32) * sprite.height;
  172. for (unsigned int i=0; i<sprite.height; i++)
  173. {
  174. //get position of the line
  175. currentOffset=BaseOffset + SDL_SwapLE32(read_unaligned_u32(RWEntriesLoc + i));
  176. unsigned int TotalRowLength = 0;
  177. while (TotalRowLength<sprite.width)
  178. {
  179. unsigned char type=FDef[currentOffset++];
  180. unsigned int length=FDef[currentOffset++] + 1;
  181. if (type==0xFF)//Raw data
  182. {
  183. loader.Load(length, FDef + currentOffset);
  184. currentOffset+=length;
  185. }
  186. else// RLE
  187. {
  188. loader.Load(length, type);
  189. }
  190. TotalRowLength += length;
  191. }
  192. loader.EndLine();
  193. }
  194. break;
  195. }
  196. case 2:
  197. {
  198. currentOffset = BaseOffset + SDL_SwapLE16(read_unaligned_u16(FDef + BaseOffset));
  199. for (unsigned int i=0; i<sprite.height; i++)
  200. {
  201. unsigned int TotalRowLength=0;
  202. while (TotalRowLength<sprite.width)
  203. {
  204. unsigned char SegmentType=FDef[currentOffset++];
  205. unsigned char code = SegmentType / 32;
  206. unsigned char length = (SegmentType & 31) + 1;
  207. if (code==7)//Raw data
  208. {
  209. loader.Load(length, FDef[currentOffset]);
  210. currentOffset += length;
  211. }
  212. else//RLE
  213. {
  214. loader.Load(length, code);
  215. }
  216. TotalRowLength+=length;
  217. }
  218. loader.EndLine();
  219. }
  220. break;
  221. }
  222. case 3:
  223. {
  224. for (unsigned int i=0; i<sprite.height; i++)
  225. {
  226. currentOffset = BaseOffset + SDL_SwapLE16(read_unaligned_u16(FDef + BaseOffset+i*2*(sprite.width/32)));
  227. unsigned int TotalRowLength=0;
  228. while (TotalRowLength<sprite.width)
  229. {
  230. unsigned char segment = FDef[currentOffset++];
  231. unsigned char code = segment / 32;
  232. unsigned char length = (segment & 31) + 1;
  233. if (code==7)//Raw data
  234. {
  235. loader.Load(length, FDef + currentOffset);
  236. currentOffset += length;
  237. }
  238. else//RLE
  239. {
  240. loader.Load(length, code);
  241. }
  242. TotalRowLength += length;
  243. }
  244. loader.EndLine();
  245. }
  246. break;
  247. }
  248. default:
  249. tlog0<<"Error: unsupported format of def file:"<<sprite.format<<"\n";
  250. break;
  251. }
  252. };
  253. CDefFile::~CDefFile()
  254. {
  255. delete[] data;
  256. delete[] palette;
  257. }
  258. const std::map<size_t, std::vector <size_t> > * CDefFile::getEntries() const
  259. {
  260. return &offset;
  261. }
  262. /*************************************************************************
  263. * Classes for image loaders - helpers for loading from def files *
  264. *************************************************************************/
  265. SDLImageLoader::SDLImageLoader(SDLImage * Img):
  266. image(Img),
  267. lineStart(NULL),
  268. position(NULL)
  269. {
  270. }
  271. void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal)
  272. {
  273. //Init image
  274. image->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SpriteSize.x, SpriteSize.y, 8, 0, 0, 0, 0);
  275. image->margins = Margins;
  276. image->fullSize = FullSize;
  277. //Prepare surface
  278. SDL_SetColors(image->surf, pal, 0, 256);
  279. SDL_LockSurface(image->surf);
  280. lineStart = position = (ui8*)image->surf->pixels;
  281. }
  282. inline void SDLImageLoader::Load(size_t size, const ui8 * data)
  283. {
  284. if (size)
  285. {
  286. memcpy((void *)position, data, size);
  287. position += size;
  288. }
  289. }
  290. inline void SDLImageLoader::Load(size_t size, ui8 color)
  291. {
  292. if (size)
  293. {
  294. memset((void *)position, color, size);
  295. position += size;
  296. }
  297. }
  298. inline void SDLImageLoader::EndLine()
  299. {
  300. lineStart += image->surf->pitch;
  301. position = lineStart;
  302. }
  303. SDLImageLoader::~SDLImageLoader()
  304. {
  305. SDL_UnlockSurface(image->surf);
  306. SDL_SetColorKey(image->surf, SDL_SRCCOLORKEY, 0);
  307. //TODO: RLE if compressed and bpp>1
  308. }
  309. ////////////////////////////////////////////////////////////////////////////////
  310. CompImageLoader::CompImageLoader(CompImage * Img):
  311. image(Img),
  312. position(NULL),
  313. entry(NULL),
  314. currentLine(0)
  315. {
  316. }
  317. void CompImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal)
  318. {
  319. image->sprite = Rect(Margins, SpriteSize);
  320. image->fullSize = FullSize;
  321. if (SpriteSize.x && SpriteSize.y)
  322. {
  323. image->palette = new SDL_Color[256];
  324. memcpy((void*)image->palette, (void*)pal, 256*sizeof(SDL_Color));
  325. //Allocate enought space for worst possible case, c-style malloc used due to resizing after load
  326. image->surf = (ui8*)malloc(SpriteSize.x*SpriteSize.y*3);
  327. image->line = new unsigned int[SpriteSize.y+1];
  328. image->line[0] = 0;
  329. position = image->surf;
  330. }
  331. }
  332. inline void CompImageLoader::NewEntry(ui8 color, size_t size)
  333. {
  334. assert(color != 0xff);
  335. assert(size && size<256);
  336. entry = position;
  337. entry[0] = color;
  338. entry[1] = size;
  339. position +=2;
  340. }
  341. inline void CompImageLoader::NewEntry(const ui8 * &data, size_t size)
  342. {
  343. assert(size && size<256);
  344. entry = position;
  345. entry[0] = 0xff;
  346. entry[1] = size;
  347. position +=2;
  348. memcpy(position, data, size);
  349. position+=size;
  350. data+=size;
  351. }
  352. inline ui8 CompImageLoader::typeOf(ui8 color)
  353. {
  354. if (color == 0)
  355. return 0;
  356. if (image->palette[color].unused != 255)
  357. return 1;
  358. return 2;
  359. }
  360. inline void CompImageLoader::Load(size_t size, const ui8 * data)
  361. {
  362. while (size)
  363. {
  364. //Try to compress data
  365. while(true)
  366. {
  367. ui8 color = data[0];
  368. if (color != 0xff)
  369. {
  370. size_t runLength = 1;
  371. while (runLength < size && color == data[runLength])
  372. runLength++;
  373. if (runLength > 1)//Row of one color found - use RLE
  374. {
  375. Load(runLength, color);
  376. data += runLength;
  377. size -= runLength;
  378. if (!size)
  379. return;
  380. }
  381. else
  382. break;
  383. }
  384. else
  385. break;
  386. }
  387. //Select length for new raw entry
  388. size_t runLength = 1;
  389. ui8 color = data[0];
  390. ui8 type = typeOf(color);
  391. ui8 color2;
  392. ui8 type2;
  393. if (size > 1)
  394. {
  395. do
  396. {
  397. color2 = data[runLength];
  398. type2 = typeOf(color2);
  399. runLength++;
  400. }
  401. //While we have data of this type and different colors
  402. while ((runLength < size) && (type == type2) && ( (color2 != 0xff) || (color2 != color)));
  403. }
  404. size -= runLength;
  405. //add data to last entry
  406. if (entry && entry[0] == 0xff && type == typeOf(entry[2]))
  407. {
  408. size_t toCopy = std::min<size_t>(runLength, 255 - entry[1]);
  409. runLength -= toCopy;
  410. entry[1] += toCopy;
  411. memcpy(position, data, toCopy);
  412. data+=toCopy;
  413. position+=toCopy;
  414. }
  415. //Create new entries
  416. while (runLength > 255)
  417. {
  418. NewEntry(data, 255);
  419. runLength -= 255;
  420. }
  421. if (runLength)
  422. NewEntry(data, runLength);
  423. }
  424. }
  425. inline void CompImageLoader::Load(size_t size, ui8 color)
  426. {
  427. if (!size)
  428. return;
  429. if (color==0xff)
  430. {
  431. ui8* tmpbuf = new ui8[size];
  432. memset((void*)tmpbuf, color, size);
  433. Load(size, tmpbuf);
  434. delete [] tmpbuf;
  435. return;
  436. }
  437. //Current entry is RLE with same color as new block
  438. if (entry && entry[0] == color)
  439. {
  440. size_t toCopy = std::min<size_t>(size, 255 - entry[1]);
  441. entry[1] = 255;
  442. size -= toCopy;
  443. entry[1] += toCopy;
  444. }
  445. //Create new entries
  446. while (size > 255)
  447. {
  448. NewEntry(color, 255);
  449. size -= 255;
  450. }
  451. if (size)
  452. NewEntry(color, size);
  453. }
  454. void CompImageLoader::EndLine()
  455. {
  456. currentLine++;
  457. image->line[currentLine] = position - image->surf;
  458. entry = NULL;
  459. }
  460. CompImageLoader::~CompImageLoader()
  461. {
  462. if (!image->surf)
  463. return;
  464. ui8* newPtr = (ui8*)realloc((void*)image->surf, position - image->surf);
  465. if (newPtr)
  466. image->surf = newPtr;
  467. }
  468. /*************************************************************************
  469. * Classes for images, support loading from file and drawing on surface *
  470. *************************************************************************/
  471. IImage::IImage():
  472. refCount(1)
  473. {
  474. }
  475. bool IImage::decreaseRef()
  476. {
  477. refCount--;
  478. return refCount <= 0;
  479. }
  480. void IImage::increaseRef()
  481. {
  482. refCount++;
  483. }
  484. SDLImage::SDLImage(CDefFile *data, size_t frame, size_t group, bool compressed):
  485. surf(NULL)
  486. {
  487. SDLImageLoader loader(this);
  488. data->loadFrame(frame, group, loader);
  489. }
  490. SDLImage::SDLImage(SDL_Surface * from, bool extraRef):
  491. margins(0,0)
  492. {
  493. surf = from;
  494. if (extraRef)
  495. surf->refcount++;
  496. fullSize.x = surf->w;
  497. fullSize.y = surf->h;
  498. }
  499. SDLImage::SDLImage(std::string filename, bool compressed):
  500. margins(0,0)
  501. {
  502. int size;
  503. unsigned char * pic = spriteh->giveFile(filename, FILE_GRAPHICS, &size);
  504. surf = IMG_Load_RW( SDL_RWFromMem((void*)pic, size), 1);
  505. fullSize.x = surf->w;
  506. fullSize.y = surf->h;
  507. delete [] pic;
  508. }
  509. void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
  510. {
  511. Rect sourceRect(margins.x, margins.y, surf->w, surf->h);
  512. //TODO: rotation and scaling
  513. if (src)
  514. {
  515. sourceRect = sourceRect & *src;
  516. }
  517. Rect destRect(posX, posY, surf->w, surf->h);
  518. destRect += sourceRect.topLeft();
  519. sourceRect -= margins;
  520. CSDL_Ext::blitSurface(surf, &sourceRect, where, &destRect);
  521. }
  522. void SDLImage::playerColored(int player)
  523. {
  524. graphics->blueToPlayersAdv(surf, player);
  525. }
  526. int SDLImage::width() const
  527. {
  528. return fullSize.x;
  529. }
  530. int SDLImage::height() const
  531. {
  532. return fullSize.y;
  533. }
  534. SDLImage::~SDLImage()
  535. {
  536. SDL_FreeSurface(surf);
  537. }
  538. CompImage::CompImage(const CDefFile *data, size_t frame, size_t group):
  539. surf(NULL),
  540. line(NULL),
  541. palette(NULL)
  542. {
  543. CompImageLoader loader(this);
  544. data->loadFrame(frame, group, loader);
  545. }
  546. CompImage::CompImage(SDL_Surface * surf)
  547. {
  548. //TODO
  549. assert(0);
  550. }
  551. void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src) const
  552. {
  553. if (!surf)
  554. return;
  555. Rect sourceRect(sprite);
  556. //TODO: rotation and scaling
  557. if (src)
  558. sourceRect = sourceRect & *src;
  559. //Limit source rect to sizes of surface
  560. sourceRect = sourceRect & Rect(0, 0, where->w, where->h);
  561. //Starting point on SDL surface
  562. Point dest(posX+sourceRect.x, posY+sourceRect.y);
  563. sourceRect -= sprite.topLeft();
  564. for (int currY = 0; currY <sourceRect.h; currY++)
  565. {
  566. ui8* data = surf + line[currY+sourceRect.y];
  567. ui8 type = *(data++);
  568. ui8 size = *(data++);
  569. int currX = sourceRect.x;
  570. //Skip blocks until starting position reached
  571. while ( currX > size )
  572. {
  573. currX -= size;
  574. if (type == 0xff)
  575. data += size;
  576. type = *(data++);
  577. size = *(data++);
  578. }
  579. //This block will be shown partially - calculate size\position
  580. size -= currX;
  581. if (type == 0xff)
  582. data += currX;
  583. currX = 0;
  584. ui8 bpp = where->format->BytesPerPixel;
  585. //Calculate position for blitting: pixels + Y + X
  586. ui8* blitPos = (ui8*) where->pixels;
  587. blitPos += (dest.y + currY) * where->pitch;
  588. blitPos += dest.x * bpp;
  589. //Blit block that must be fully visible
  590. while (currX + size < sourceRect.w)
  591. {
  592. //blit block, pointers will be incremented if needed
  593. BlitBlockWithBpp(bpp, type, size, data, blitPos);
  594. currX += size;
  595. type = *(data++);
  596. size = *(data++);
  597. }
  598. //Blit last, semi-visible block
  599. size = sourceRect.w - currX;
  600. BlitBlockWithBpp(bpp, type, size, data, blitPos);
  601. }
  602. }
  603. void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
  604. {
  605. switch (bpp)
  606. {
  607. case 2: BlitBlock<2>(type, size, data, dest);
  608. break;
  609. case 3: BlitBlock<3>(type, size, data, dest);
  610. break;
  611. case 4: BlitBlock<4>(type, size, data, dest);
  612. break;
  613. default:
  614. assert(0);
  615. break;
  616. }
  617. }
  618. //Blit one block from RLE-d surface
  619. template<int bpp>
  620. void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest) const
  621. {
  622. //Raw data
  623. if (type == 0xff)
  624. {
  625. ui8 color = *data;
  626. if (palette[color].unused == 255)
  627. {
  628. //Put row of RGB data
  629. for (int i=0; i<size; i++)
  630. ColorPutter<bpp, 1>::PutColor(dest, palette[*(data++)]);
  631. }
  632. else
  633. {
  634. //Put row of RGBA data
  635. for (int i=0; i<size; i++)
  636. ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[*(data++)]);
  637. }
  638. }
  639. //RLE-d sequence
  640. else
  641. {
  642. switch (palette[type].unused)
  643. {
  644. case 0:
  645. {
  646. //Skip row
  647. dest += size*bpp;
  648. break;
  649. }
  650. case 255:
  651. {
  652. //Put RGB row
  653. //FIXME: can be optimized
  654. for (int i=0; i<size; i++)
  655. ColorPutter<bpp, 1>::PutColor(dest, palette[type]);
  656. break;
  657. }
  658. default:
  659. {
  660. //Put RGBA row
  661. //FIXME: can be optimized
  662. for (int i=0; i<size; i++)
  663. ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[type]);
  664. break;
  665. }
  666. }
  667. }
  668. }
  669. void CompImage::playerColored(int player)
  670. {
  671. SDL_Color *pal = NULL;
  672. if(player < PLAYER_LIMIT && player >= 0)
  673. {
  674. pal = graphics->playerColorPalette + 32*player;
  675. }
  676. else if(player == 255 || player == -1)
  677. {
  678. pal = graphics->neutralColorPalette;
  679. }
  680. else
  681. assert(0);
  682. for(int i=0; i<32; ++i)
  683. {
  684. palette[224+i].r = pal[i].r;
  685. palette[224+i].g = pal[i].g;
  686. palette[224+i].b = pal[i].b;
  687. palette[224+i].unused = pal[i].unused;
  688. }
  689. }
  690. int CompImage::width() const
  691. {
  692. return fullSize.x;
  693. }
  694. int CompImage::height() const
  695. {
  696. return fullSize.y;
  697. }
  698. CompImage::~CompImage()
  699. {
  700. free(surf);
  701. delete [] line;
  702. delete [] palette;
  703. }
  704. /*************************************************************************
  705. * CAnimation for animations handling, can load part of file if needed *
  706. *************************************************************************/
  707. TextParser::TextParser(const std::string &name):
  708. type(0),
  709. position(std::string::npos)
  710. {
  711. if (!spriteh->haveFile(name, FILE_TEXT))
  712. return;
  713. text = spriteh->getTextFile(name);
  714. position = text.find('\n');
  715. std::string typeStr = text.substr(0, position);
  716. boost::algorithm::trim(typeStr);
  717. if (typeStr == "Replace")
  718. type = 1;
  719. else if (typeStr == "Append")
  720. type = 2;
  721. }
  722. int TextParser::getType() const
  723. {
  724. return type;
  725. }
  726. void TextParser::parseFile(std::map<size_t, std::vector <std::string> > &result)
  727. {
  728. while (position != std::string::npos)
  729. {
  730. size_t lineStart = position+1;
  731. position = text.find('\n', lineStart);
  732. std::string buf = text.substr(lineStart, position-lineStart);
  733. size_t currentBlock = atoi(buf.c_str());
  734. while (position != std::string::npos)
  735. {
  736. lineStart = position+1;
  737. position = text.find('\n', lineStart);
  738. std::string res = text.substr(lineStart, position-lineStart);
  739. boost::algorithm::trim(res);
  740. if (res.empty())
  741. break;
  742. result[currentBlock].push_back(res);
  743. }
  744. }
  745. }
  746. bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
  747. {
  748. if (size(group) <= frame)
  749. {
  750. printError(frame, group, "LoadFrame");
  751. return false;
  752. }
  753. IImage *image = getImage(frame, group, false);
  754. if (image)
  755. {
  756. image->increaseRef();
  757. return true;
  758. }
  759. //try to get image from def
  760. if (source[group][frame].empty())
  761. {
  762. if (compressed)
  763. images[group][frame] = new CompImage(file, frame, group);
  764. else
  765. images[group][frame] = new SDLImage(file, frame, group);
  766. }
  767. else //load from separate file
  768. {
  769. //TODO: compressed images
  770. images[group][frame] = new SDLImage(source[group][frame].c_str());
  771. return true;
  772. }
  773. return false;
  774. }
  775. bool CAnimation::unloadFrame(size_t frame, size_t group)
  776. {
  777. IImage *image = getImage(frame, group, false);
  778. if (image)
  779. {
  780. //decrease ref count for image and delete if needed
  781. if (image->decreaseRef())
  782. {
  783. delete image;
  784. images[group].erase(frame);
  785. }
  786. if (images[group].empty())
  787. images.erase(group);
  788. return true;
  789. }
  790. return false;
  791. }
  792. void CAnimation::init(CDefFile * file)
  793. {
  794. TextParser txtFile(name);
  795. if ( txtFile.getType() != 1 )
  796. {
  797. const std::map<size_t, std::vector <size_t> > * defEntries = file->getEntries();
  798. for (std::map<size_t, std::vector <size_t> >::const_iterator mapIt = defEntries->begin(); mapIt!=defEntries->end(); ++mapIt)
  799. source[mapIt->first].resize(mapIt->second.size());
  800. }
  801. txtFile.parseFile(source);
  802. }
  803. CDefFile * CAnimation::getFile() const
  804. {
  805. if (spriteh->haveFile(name, FILE_ANIMATION))
  806. return new CDefFile(name);
  807. return NULL;
  808. }
  809. void CAnimation::printError(size_t frame, size_t group, std::string type) const
  810. {
  811. tlog0 << type <<" error: Request for frame not present in CAnimation!\n"
  812. <<"\tFile name: "<<name<<" Group: "<<group<<" Frame: "<<frame<<"\n";
  813. }
  814. CAnimation::CAnimation(std::string Name, bool Compressed):
  815. name(Name),
  816. compressed(Compressed)
  817. {
  818. size_t dotPos = name.find_last_of('.');
  819. if ( dotPos!=-1 )
  820. name.erase(dotPos);
  821. std::transform(name.begin(), name.end(), name.begin(), toupper);
  822. CDefFile * file = getFile();
  823. init(file);
  824. delete file;
  825. }
  826. CAnimation::CAnimation():
  827. name(""),
  828. compressed(false)
  829. {
  830. }
  831. CAnimation::~CAnimation()
  832. {
  833. for (group_map::iterator group = images.begin(); group != images.end(); ++group )
  834. for (image_map::iterator image = group->second.begin(); image != group->second.end(); ++image )
  835. delete image->second;
  836. }
  837. void CAnimation::setCustom(IImage * newImage, size_t frame, size_t group)
  838. {
  839. assert(newImage);
  840. IImage * oldImage = getImage(frame,group,false);
  841. if (oldImage);
  842. delete oldImage;
  843. images[group][frame] = newImage;
  844. if (source[group].size() <= frame)
  845. source[group].resize(frame+1);
  846. }
  847. IImage * CAnimation::getImage(size_t frame, size_t group, bool verbose) const
  848. {
  849. group_map::const_iterator groupIter = images.find(group);
  850. if (groupIter != images.end())
  851. {
  852. image_map::const_iterator imageIter = groupIter->second.find(frame);
  853. if (imageIter != groupIter->second.end())
  854. return imageIter->second;
  855. }
  856. if (verbose)
  857. printError(frame, group, "GetImage");
  858. return NULL;
  859. }
  860. void CAnimation::load()
  861. {
  862. CDefFile * file = getFile();
  863. for (source_map::iterator group = source.begin(); group != source.end(); ++group )
  864. for (size_t image=0; image < group->second.size(); image++)
  865. loadFrame(file, image, group->first);
  866. delete file;
  867. }
  868. void CAnimation::unload()
  869. {
  870. for (source_map::iterator group = source.begin(); group != source.end(); ++group )
  871. for (size_t image=0; image < group->second.size(); image++)
  872. unloadFrame(image, group->first);
  873. }
  874. void CAnimation::loadGroup(size_t group)
  875. {
  876. CDefFile * file = getFile();
  877. if (vstd::contains(source, group))
  878. for (size_t image=0; image < source[group].size(); image++)
  879. loadFrame(file, image, group);
  880. delete file;
  881. }
  882. void CAnimation::unloadGroup(size_t group)
  883. {
  884. if (vstd::contains(source, group))
  885. for (size_t image=0; image < source[group].size(); image++)
  886. unloadFrame(image, group);
  887. }
  888. void CAnimation::load(size_t frame, size_t group)
  889. {
  890. CDefFile * file = getFile();
  891. loadFrame(file, frame, group);
  892. delete file;
  893. }
  894. void CAnimation::unload(size_t frame, size_t group)
  895. {
  896. unloadFrame(frame, group);
  897. }
  898. void CAnimation::fixButtonPos()
  899. {
  900. group_map::iterator groupIter = images.find(0);
  901. if (groupIter != images.end())
  902. {
  903. image_map::iterator first = groupIter->second.find(0),
  904. second = groupIter->second.find(1);
  905. if (first != second)
  906. {
  907. std::swap (first->second, second->second);
  908. }
  909. }
  910. }
  911. size_t CAnimation::size(size_t group) const
  912. {
  913. source_map::const_iterator iter = source.find(group);
  914. if (iter != source.end())
  915. return iter->second.size();
  916. return 0;
  917. }
  918. CAnimImage::CAnimImage(int x, int y, std::string name, size_t Frame, size_t Group):
  919. anim(name),
  920. frame(Frame),
  921. group(Group)
  922. {
  923. anim.load(frame, group);
  924. pos.w = anim.getImage(frame, group)->width();
  925. pos.h = anim.getImage(frame, group)->height();
  926. }
  927. CAnimImage::~CAnimImage()
  928. {
  929. }
  930. void CAnimImage::showAll(SDL_Surface *to)
  931. {
  932. anim.getImage(frame, group)->draw(to);
  933. }
  934. void CAnimImage::setFrame(size_t Frame, size_t Group)
  935. {
  936. if (frame == Frame && group==Group)
  937. return;
  938. if (anim.size(Group) > Frame)
  939. {
  940. anim.unload(frame, group);
  941. anim.load(Frame, Group);
  942. frame = Frame;
  943. group = Group;
  944. }
  945. }
  946. CShowableAnim::CShowableAnim(int x, int y, std::string name, unsigned char Flags, unsigned int Delay, size_t Group):
  947. anim(name, Flags & USE_RLE),
  948. group(Group),
  949. frame(0),
  950. first(0),
  951. frameDelay(Delay),
  952. value(0),
  953. flags(Flags),
  954. xOffset(0),
  955. yOffset(0)
  956. {
  957. anim.loadGroup(group);
  958. last = anim.size(group);
  959. pos.w = anim.getImage(0, group)->width();
  960. pos.h = anim.getImage(0, group)->height();
  961. pos.x+= x;
  962. pos.y+= y;
  963. }
  964. CShowableAnim::~CShowableAnim()
  965. {
  966. }
  967. bool CShowableAnim::set(size_t Group, size_t from, size_t to)
  968. {
  969. size_t max = anim.size(Group);
  970. if (max>to)
  971. max = to;
  972. if (max < from || max == 0)
  973. return false;
  974. anim.load(Group);
  975. anim.unload(group);
  976. group = Group;
  977. frame = first = from;
  978. last = max;
  979. value = 0;
  980. return true;
  981. }
  982. bool CShowableAnim::set(size_t Group)
  983. {
  984. if (anim.size(Group)== 0)
  985. return false;
  986. if (group != Group)
  987. {
  988. anim.loadGroup(Group);
  989. anim.unloadGroup(group);
  990. first = 0;
  991. group = Group;
  992. last = anim.size(Group);
  993. }
  994. frame = value = 0;
  995. return true;
  996. }
  997. void CShowableAnim::reset()
  998. {
  999. value = 0;
  1000. frame = first;
  1001. if (callback)
  1002. callback();
  1003. }
  1004. void CShowableAnim::clipRect(int posX, int posY, int width, int height)
  1005. {
  1006. xOffset = posX;
  1007. yOffset = posY;
  1008. pos.w = width;
  1009. pos.h = height;
  1010. }
  1011. void CShowableAnim::show(SDL_Surface *to)
  1012. {
  1013. if ( flags & BASE && frame != first)
  1014. blitImage(first, group, to);
  1015. blitImage(frame, group, to);
  1016. if ( ++value == frameDelay )
  1017. {
  1018. value = 0;
  1019. if ( ++frame == last)
  1020. reset();
  1021. }
  1022. }
  1023. void CShowableAnim::showAll(SDL_Surface *to)
  1024. {
  1025. if ( flags & BASE && frame != first)
  1026. blitImage(first, group, to);
  1027. blitImage(frame, group, to);
  1028. }
  1029. void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
  1030. {
  1031. assert(to);
  1032. Rect src( xOffset, yOffset, pos.w, pos.h);
  1033. IImage * img = anim.getImage(frame, group);
  1034. img->draw(to, pos.x-xOffset, pos.y-yOffset, &src);
  1035. }
  1036. void CShowableAnim::rotate(bool on, bool vertical)
  1037. {
  1038. unsigned char flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
  1039. if (on)
  1040. flags |= flag;
  1041. else
  1042. flags &= ~flag;
  1043. }
  1044. CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, unsigned char flags, EAnimType type):
  1045. CShowableAnim(x,y,name,flags,3,type)
  1046. {
  1047. xOffset = picPos.x;
  1048. yOffset = picPos.y;
  1049. if (picPos.w)
  1050. pos.w = picPos.w;
  1051. if (picPos.h)
  1052. pos.h = picPos.h;
  1053. };
  1054. void CCreatureAnim::loopPreview()
  1055. {
  1056. std::vector<EAnimType> available;
  1057. static const EAnimType previewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
  1058. for (size_t i=0; i<5; i++)
  1059. if (anim.size(previewList[i]))
  1060. available.push_back(previewList[i]);
  1061. size_t rnd = rand()%(available.size()*2);
  1062. if (rnd >= available.size())
  1063. {
  1064. if ( anim.size(MOVING) == 0 )//no moving animation present
  1065. addLast( HOLDING );
  1066. else
  1067. addLast( MOVING ) ;
  1068. }
  1069. else
  1070. addLast(available[rnd]);
  1071. }
  1072. void CCreatureAnim::addLast(EAnimType newType)
  1073. {
  1074. if (type != MOVING && newType == MOVING)//starting moving - play init sequence
  1075. {
  1076. queue.push( MOVE_START );
  1077. }
  1078. else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
  1079. {
  1080. queue.push( MOVE_END );
  1081. }
  1082. if (newType == TURN_L || newType == TURN_R)
  1083. queue.push(newType);
  1084. queue.push(newType);
  1085. }
  1086. void CCreatureAnim::reset()
  1087. {
  1088. //if we are in the middle of rotation - set flag
  1089. if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
  1090. rotate(true);
  1091. if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
  1092. rotate(false);
  1093. while (!queue.empty())
  1094. {
  1095. EAnimType at = queue.front();
  1096. queue.pop();
  1097. if (set(at))
  1098. return;
  1099. }
  1100. if (callback)
  1101. callback();
  1102. while (!queue.empty())
  1103. {
  1104. EAnimType at = queue.front();
  1105. queue.pop();
  1106. if (set(at))
  1107. return;
  1108. }
  1109. set(type);
  1110. tlog0<<"Warning: next sequence was not found for animation!\n";
  1111. }
  1112. void CCreatureAnim::startPreview()
  1113. {
  1114. callback = boost::bind(&CCreatureAnim::loopPreview,this);
  1115. }
  1116. void CCreatureAnim::clearAndSet(EAnimType type)
  1117. {
  1118. while (!queue.empty())
  1119. queue.pop();
  1120. set(type);
  1121. }