CAnimation.cpp 32 KB

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