CAnimation.cpp 32 KB

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