CAnimation.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  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. tlog0<<"Error: file not found: "<<filename<<"\n";
  522. surf = NULL;
  523. return;
  524. }
  525. fullSize.x = surf->w;
  526. fullSize.y = surf->h;
  527. }
  528. void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, unsigned char rotation) const
  529. {
  530. if (!surf)
  531. return;
  532. Rect sourceRect(margins.x, margins.y, surf->w, surf->h);
  533. //TODO: rotation and scaling
  534. if (src)
  535. {
  536. sourceRect = sourceRect & *src;
  537. }
  538. Rect destRect(posX, posY, surf->w, surf->h);
  539. destRect += sourceRect.topLeft();
  540. sourceRect -= margins;
  541. CSDL_Ext::blitSurface(surf, &sourceRect, where, &destRect);
  542. }
  543. void SDLImage::playerColored(int player)
  544. {
  545. graphics->blueToPlayersAdv(surf, player);
  546. }
  547. int SDLImage::width() const
  548. {
  549. return fullSize.x;
  550. }
  551. int SDLImage::height() const
  552. {
  553. return fullSize.y;
  554. }
  555. SDLImage::~SDLImage()
  556. {
  557. SDL_FreeSurface(surf);
  558. }
  559. CompImage::CompImage(const CDefFile *data, size_t frame, size_t group):
  560. surf(NULL),
  561. line(NULL),
  562. palette(NULL)
  563. {
  564. CompImageLoader loader(this);
  565. data->loadFrame(frame, group, loader);
  566. }
  567. CompImage::CompImage(SDL_Surface * surf)
  568. {
  569. //TODO
  570. assert(0);
  571. }
  572. void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 alpha) const
  573. {
  574. int rotation = 0; //TODO
  575. //rotation & 2 = horizontal rotation
  576. //rotation & 4 = vertical rotation
  577. if (!surf)
  578. return;
  579. Rect sourceRect(sprite);
  580. //TODO: rotation and scaling
  581. if (src)
  582. sourceRect = sourceRect & *src;
  583. //Limit source rect to sizes of surface
  584. sourceRect = sourceRect & Rect(0, 0, where->w, where->h);
  585. //Starting point on SDL surface
  586. Point dest(posX+sourceRect.x, posY+sourceRect.y);
  587. if (rotation & 2)
  588. dest.y += sourceRect.h;
  589. if (rotation & 4)
  590. dest.x += sourceRect.w;
  591. sourceRect -= sprite.topLeft();
  592. for (int currY = 0; currY <sourceRect.h; currY++)
  593. {
  594. ui8* data = surf + line[currY+sourceRect.y];
  595. ui8 type = *(data++);
  596. ui8 size = *(data++);
  597. int currX = sourceRect.x;
  598. //Skip blocks until starting position reached
  599. while ( currX > size )
  600. {
  601. currX -= size;
  602. if (type == 0xff)
  603. data += size;
  604. type = *(data++);
  605. size = *(data++);
  606. }
  607. //This block will be shown partially - calculate size\position
  608. size -= currX;
  609. if (type == 0xff)
  610. data += currX;
  611. currX = 0;
  612. ui8 bpp = where->format->BytesPerPixel;
  613. //Calculate position for blitting: pixels + Y + X
  614. ui8* blitPos = (ui8*) where->pixels;
  615. if (rotation & 4)
  616. blitPos += (dest.y - currY) * where->pitch;
  617. else
  618. blitPos += (dest.y + currY) * where->pitch;
  619. blitPos += dest.x * bpp;
  620. //Blit blocks that must be fully visible
  621. while (currX + size < sourceRect.w)
  622. {
  623. //blit block, pointers will be modified if needed
  624. BlitBlockWithBpp(bpp, type, size, data, blitPos, alpha, rotation & 2);
  625. currX += size;
  626. type = *(data++);
  627. size = *(data++);
  628. }
  629. //Blit last, semi-visible block
  630. size = sourceRect.w - currX;
  631. BlitBlockWithBpp(bpp, type, size, data, blitPos, alpha, rotation & 2);
  632. }
  633. }
  634. #define CASEBPP(x,y) case x: BlitBlock<x,y>(type, size, data, dest, alpha); break
  635. //FIXME: better way to get blitter
  636. void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha, bool rotated) const
  637. {
  638. assert(bpp>1 && bpp<5);
  639. if (rotated)
  640. switch (bpp)
  641. {
  642. CASEBPP(2,1);
  643. CASEBPP(3,1);
  644. CASEBPP(4,1);
  645. }
  646. else
  647. switch (bpp)
  648. {
  649. CASEBPP(2,1);
  650. CASEBPP(3,1);
  651. CASEBPP(4,1);
  652. }
  653. }
  654. #undef CASEBPP
  655. //Blit one block from RLE-d surface
  656. template<int bpp, int dir>
  657. void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha) const
  658. {
  659. //Raw data
  660. if (type == 0xff)
  661. {
  662. ui8 color = *data;
  663. if (alpha != 255)//Per-surface alpha is set
  664. {
  665. for (size_t i=0; i<size; i++)
  666. {
  667. SDL_Color col = palette[*(data++)];
  668. col.unused = (unsigned int)col.unused*(255-alpha)/255;
  669. ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
  670. }
  671. return;
  672. }
  673. if (palette[color].unused == 255)
  674. {
  675. //Put row of RGB data
  676. for (size_t i=0; i<size; i++)
  677. ColorPutter<bpp, 1>::PutColor(dest, palette[*(data++)]);
  678. }
  679. else
  680. {
  681. //Put row of RGBA data
  682. for (size_t i=0; i<size; i++)
  683. ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[*(data++)]);
  684. }
  685. }
  686. //RLE-d sequence
  687. else
  688. {
  689. if (alpha != 255 && palette[type].unused !=0)//Per-surface alpha is set
  690. {
  691. SDL_Color col = palette[type];
  692. col.unused = (int)col.unused*(255-alpha)/255;
  693. for (size_t i=0; i<size; i++)
  694. ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
  695. return;
  696. }
  697. switch (palette[type].unused)
  698. {
  699. case 0:
  700. {
  701. //Skip row
  702. dest += size*bpp;
  703. break;
  704. }
  705. case 255:
  706. {
  707. //Put RGB row
  708. ColorPutter<bpp, 1>::PutColorRow(dest, palette[type], size);
  709. break;
  710. }
  711. default:
  712. {
  713. //Put RGBA row
  714. for (size_t i=0; i<size; i++)
  715. ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[type]);
  716. break;
  717. }
  718. }
  719. }
  720. }
  721. void CompImage::playerColored(int player)
  722. {
  723. SDL_Color *pal = NULL;
  724. if(player < PLAYER_LIMIT && player >= 0)
  725. {
  726. pal = graphics->playerColorPalette + 32*player;
  727. }
  728. else if(player == 255 || player == -1)
  729. {
  730. pal = graphics->neutralColorPalette;
  731. }
  732. else
  733. assert(0);
  734. for(int i=0; i<32; ++i)
  735. {
  736. palette[224+i].r = pal[i].r;
  737. palette[224+i].g = pal[i].g;
  738. palette[224+i].b = pal[i].b;
  739. palette[224+i].unused = pal[i].unused;
  740. }
  741. }
  742. int CompImage::width() const
  743. {
  744. return fullSize.x;
  745. }
  746. int CompImage::height() const
  747. {
  748. return fullSize.y;
  749. }
  750. CompImage::~CompImage()
  751. {
  752. free(surf);
  753. delete [] line;
  754. delete [] palette;
  755. }
  756. /*************************************************************************
  757. * CAnimation for animations handling, can load part of file if needed *
  758. *************************************************************************/
  759. TextParser::TextParser(const std::string &name):
  760. type(0),
  761. position(std::string::npos)
  762. {
  763. if (!spriteh->haveFile(name, FILE_TEXT))
  764. return;
  765. text = spriteh->getTextFile(name);
  766. position = text.find('\n');
  767. std::string typeStr = text.substr(0, position);
  768. boost::algorithm::trim(typeStr);
  769. if (typeStr == "Replace")
  770. type = 1;
  771. else if (typeStr == "Append")
  772. type = 2;
  773. }
  774. std::string TextParser::getLine()
  775. {
  776. size_t lineStart = position+1;
  777. position = text.find('\n', lineStart);
  778. return text.substr(lineStart, position-lineStart);
  779. }
  780. int TextParser::getType() const
  781. {
  782. return type;
  783. }
  784. void TextParser::parseFile(std::map<size_t, std::vector <std::string> > &result)
  785. {
  786. std::string baseDir = getLine();
  787. while (position != std::string::npos)
  788. {
  789. std::string buf = getLine();
  790. size_t currentBlock = atoi(buf.c_str());
  791. while (position != std::string::npos)
  792. {
  793. std::string res = getLine();
  794. boost::algorithm::trim(res);
  795. if (res.empty())
  796. break;
  797. result[currentBlock].push_back(baseDir+'/'+res);
  798. }
  799. }
  800. }
  801. IImage * CAnimation::getFromExtraDef(std::string filename)
  802. {
  803. size_t pos = filename.find(':');
  804. if (pos == -1)
  805. return NULL;
  806. CAnimation anim(filename.substr(0, pos));
  807. pos++;
  808. size_t frame = atoi(filename.c_str()+pos);
  809. size_t group = 0;
  810. pos = filename.find(':', pos);
  811. if (pos != -1)
  812. {
  813. group = frame;
  814. frame = atoi(filename.c_str()+pos);
  815. }
  816. anim.load(frame ,group);
  817. IImage * ret = anim.images[group][frame];
  818. anim.images.clear();
  819. return ret;
  820. }
  821. bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
  822. {
  823. if (size(group) <= frame)
  824. {
  825. printError(frame, group, "LoadFrame");
  826. return false;
  827. }
  828. IImage *image = getImage(frame, group, false);
  829. if (image)
  830. {
  831. image->increaseRef();
  832. return true;
  833. }
  834. //try to get image from def
  835. if (source[group][frame].empty())
  836. {
  837. if (compressed)
  838. images[group][frame] = new CompImage(file, frame, group);
  839. else
  840. images[group][frame] = new SDLImage(file, frame, group);
  841. }
  842. else //load from separate file
  843. {
  844. IImage * img = getFromExtraDef(source[group][frame].c_str());
  845. if (!img)//TODO: load compressed image
  846. img = new SDLImage(source[group][frame].c_str());
  847. images[group][frame] = img;
  848. return true;
  849. }
  850. return false;
  851. }
  852. bool CAnimation::unloadFrame(size_t frame, size_t group)
  853. {
  854. IImage *image = getImage(frame, group, false);
  855. if (image)
  856. {
  857. //decrease ref count for image and delete if needed
  858. if (image->decreaseRef())
  859. {
  860. delete image;
  861. images[group].erase(frame);
  862. }
  863. if (images[group].empty())
  864. images.erase(group);
  865. return true;
  866. }
  867. return false;
  868. }
  869. void CAnimation::init(CDefFile * file)
  870. {
  871. TextParser txtFile(name);
  872. if ( file && txtFile.getType() != 1 )
  873. {
  874. const std::map<size_t, size_t> defEntries = file->getEntries();
  875. for (std::map<size_t, size_t>::const_iterator mapIt = defEntries.begin(); mapIt!=defEntries.end(); ++mapIt)
  876. source[mapIt->first].resize(mapIt->second);
  877. }
  878. txtFile.parseFile(source);
  879. }
  880. CDefFile * CAnimation::getFile() const
  881. {
  882. if (spriteh->haveFile(name, FILE_ANIMATION))
  883. return new CDefFile(name);
  884. return NULL;
  885. }
  886. void CAnimation::printError(size_t frame, size_t group, std::string type) const
  887. {
  888. tlog0 << type <<" error: Request for frame not present in CAnimation!\n"
  889. <<"\tFile name: "<<name<<" Group: "<<group<<" Frame: "<<frame<<"\n";
  890. }
  891. CAnimation::CAnimation(std::string Name, bool Compressed):
  892. name(Name),
  893. compressed(Compressed)
  894. {
  895. size_t dotPos = name.find_last_of('.');
  896. if ( dotPos!=-1 )
  897. name.erase(dotPos);
  898. std::transform(name.begin(), name.end(), name.begin(), toupper);
  899. CDefFile * file = getFile();
  900. init(file);
  901. delete file;
  902. loadedAnims.insert(this);
  903. }
  904. CAnimation::CAnimation():
  905. name(""),
  906. compressed(false)
  907. {
  908. init(NULL);
  909. loadedAnims.insert(this);
  910. }
  911. CAnimation::~CAnimation()
  912. {
  913. if (!images.empty())
  914. {
  915. tlog2<<"Warning: not all frames were unloaded from "<<name<<"\n";
  916. for (group_map::iterator group = images.begin(); group != images.end(); ++group )
  917. for (image_map::iterator image = group->second.begin(); image != group->second.end(); ++image )
  918. delete image->second;
  919. }
  920. loadedAnims.erase(this);
  921. }
  922. void CAnimation::setCustom(std::string filename, size_t frame, size_t group)
  923. {
  924. if (source[group].size() <= frame)
  925. source[group].resize(frame+1);
  926. source[group][frame] = filename;
  927. //FIXME: update image if already loaded
  928. }
  929. IImage * CAnimation::getImage(size_t frame, size_t group, bool verbose) const
  930. {
  931. group_map::const_iterator groupIter = images.find(group);
  932. if (groupIter != images.end())
  933. {
  934. image_map::const_iterator imageIter = groupIter->second.find(frame);
  935. if (imageIter != groupIter->second.end())
  936. return imageIter->second;
  937. }
  938. if (verbose)
  939. printError(frame, group, "GetImage");
  940. return NULL;
  941. }
  942. void CAnimation::load()
  943. {
  944. CDefFile * file = getFile();
  945. for (source_map::iterator group = source.begin(); group != source.end(); ++group )
  946. for (size_t image=0; image < group->second.size(); image++)
  947. loadFrame(file, image, group->first);
  948. delete file;
  949. }
  950. void CAnimation::unload()
  951. {
  952. for (source_map::iterator group = source.begin(); group != source.end(); ++group )
  953. for (size_t image=0; image < group->second.size(); image++)
  954. unloadFrame(image, group->first);
  955. }
  956. void CAnimation::loadGroup(size_t group)
  957. {
  958. CDefFile * file = getFile();
  959. if (vstd::contains(source, group))
  960. for (size_t image=0; image < source[group].size(); image++)
  961. loadFrame(file, image, group);
  962. delete file;
  963. }
  964. void CAnimation::unloadGroup(size_t group)
  965. {
  966. if (vstd::contains(source, group))
  967. for (size_t image=0; image < source[group].size(); image++)
  968. unloadFrame(image, group);
  969. }
  970. void CAnimation::load(size_t frame, size_t group)
  971. {
  972. CDefFile * file = getFile();
  973. loadFrame(file, frame, group);
  974. delete file;
  975. }
  976. void CAnimation::unload(size_t frame, size_t group)
  977. {
  978. unloadFrame(frame, group);
  979. }
  980. size_t CAnimation::size(size_t group) const
  981. {
  982. source_map::const_iterator iter = source.find(group);
  983. if (iter != source.end())
  984. return iter->second.size();
  985. return 0;
  986. }
  987. std::set<CAnimation*> CAnimation::loadedAnims;
  988. void CAnimation::getAnimInfo()
  989. {
  990. tlog1<<"Animation stats: Loaded "<<loadedAnims.size()<<" total\n";
  991. for (std::set<CAnimation*>::iterator it = loadedAnims.begin(); it != loadedAnims.end(); it++)
  992. {
  993. CAnimation * anim = *it;
  994. tlog1<<"Name: "<<anim->name<<" Groups: "<<anim->images.size();
  995. if (!anim->images.empty())
  996. tlog1<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
  997. tlog1<<"\n";
  998. }
  999. }
  1000. CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, unsigned char Flags):
  1001. frame(Frame),
  1002. group(Group),
  1003. player(-1),
  1004. flags(Flags)
  1005. {
  1006. pos.x += x;
  1007. pos.y += y;
  1008. anim = new CAnimation(name);
  1009. init();
  1010. }
  1011. CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, unsigned char Flags):
  1012. anim(Anim),
  1013. frame(Frame),
  1014. group(Group),
  1015. player(-1),
  1016. flags(Flags)
  1017. {
  1018. pos.x += x;
  1019. pos.y += y;
  1020. init();
  1021. }
  1022. void CAnimImage::init()
  1023. {
  1024. anim->load(frame, group);
  1025. if (flags & CShowableAnim::BASE)
  1026. anim->load(0,group);
  1027. IImage *img = anim->getImage(frame, group);
  1028. if (img)
  1029. {
  1030. pos.w = img->width();
  1031. pos.h = img->height();
  1032. }
  1033. }
  1034. CAnimImage::~CAnimImage()
  1035. {
  1036. anim->unload(frame, group);
  1037. if (flags & CShowableAnim::BASE)
  1038. anim->unload(0,group);
  1039. delete anim;
  1040. }
  1041. void CAnimImage::showAll(SDL_Surface *to)
  1042. {
  1043. IImage *img = anim->getImage(frame, group);
  1044. if (img)
  1045. img->draw(to, pos.x, pos.y);
  1046. }
  1047. void CAnimImage::setFrame(size_t Frame, size_t Group)
  1048. {
  1049. if (frame == Frame && group==Group)
  1050. return;
  1051. if (anim->size(Group) > Frame)
  1052. {
  1053. anim->load(Frame, Group);
  1054. anim->unload(frame, group);
  1055. frame = Frame;
  1056. group = Group;
  1057. IImage *img = anim->getImage(frame, group);
  1058. if (img)
  1059. {
  1060. if (flags & CShowableAnim::PLAYER_COLORED)
  1061. img->playerColored(player);
  1062. pos.w = img->width();
  1063. pos.h = img->height();
  1064. }
  1065. }
  1066. }
  1067. void CAnimImage::playerColored(int currPlayer)
  1068. {
  1069. player = currPlayer;
  1070. flags |= CShowableAnim::PLAYER_COLORED;
  1071. anim->getImage(frame, group)->playerColored(player);
  1072. if (flags & CShowableAnim::BASE)
  1073. anim->getImage(0, group)->playerColored(player);
  1074. }
  1075. CShowableAnim::CShowableAnim(int x, int y, std::string name, unsigned char Flags, unsigned int Delay, size_t Group):
  1076. anim(name, Flags & USE_RLE),
  1077. group(Group),
  1078. frame(0),
  1079. first(0),
  1080. frameDelay(Delay),
  1081. value(0),
  1082. flags(Flags),
  1083. xOffset(0),
  1084. yOffset(0),
  1085. alpha(255)
  1086. {
  1087. anim.loadGroup(group);
  1088. last = anim.size(group);
  1089. pos.w = anim.getImage(0, group)->width();
  1090. pos.h = anim.getImage(0, group)->height();
  1091. pos.x+= x;
  1092. pos.y+= y;
  1093. }
  1094. CShowableAnim::~CShowableAnim()
  1095. {
  1096. anim.unloadGroup(group);
  1097. }
  1098. void CShowableAnim::setAlpha(unsigned int alphaValue)
  1099. {
  1100. alpha = std::min<unsigned int>(alphaValue, 255);
  1101. }
  1102. bool CShowableAnim::set(size_t Group, size_t from, size_t to)
  1103. {
  1104. size_t max = anim.size(Group);
  1105. if (max>to)
  1106. max = to;
  1107. if (max < from || max == 0)
  1108. return false;
  1109. anim.load(Group);
  1110. anim.unload(group);
  1111. group = Group;
  1112. frame = first = from;
  1113. last = max;
  1114. value = 0;
  1115. return true;
  1116. }
  1117. bool CShowableAnim::set(size_t Group)
  1118. {
  1119. if (anim.size(Group)== 0)
  1120. return false;
  1121. if (group != Group)
  1122. {
  1123. anim.loadGroup(Group);
  1124. anim.unloadGroup(group);
  1125. first = 0;
  1126. group = Group;
  1127. last = anim.size(Group);
  1128. }
  1129. frame = value = 0;
  1130. return true;
  1131. }
  1132. void CShowableAnim::reset()
  1133. {
  1134. value = 0;
  1135. frame = first;
  1136. if (callback)
  1137. callback();
  1138. }
  1139. void CShowableAnim::clipRect(int posX, int posY, int width, int height)
  1140. {
  1141. xOffset = posX;
  1142. yOffset = posY;
  1143. pos.w = width;
  1144. pos.h = height;
  1145. }
  1146. void CShowableAnim::show(SDL_Surface *to)
  1147. {
  1148. if ( flags & BASE && frame != first)
  1149. blitImage(first, group, to);
  1150. blitImage(frame, group, to);
  1151. if ( ++value == frameDelay )
  1152. {
  1153. value = 0;
  1154. if ( ++frame == last)
  1155. reset();
  1156. }
  1157. }
  1158. void CShowableAnim::showAll(SDL_Surface *to)
  1159. {
  1160. if ( flags & BASE && frame != first)
  1161. blitImage(first, group, to);
  1162. blitImage(frame, group, to);
  1163. }
  1164. void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
  1165. {
  1166. assert(to);
  1167. Rect src( xOffset, yOffset, pos.w, pos.h);
  1168. IImage * img = anim.getImage(frame, group);
  1169. if (img)
  1170. img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
  1171. }
  1172. void CShowableAnim::rotate(bool on, bool vertical)
  1173. {
  1174. unsigned char flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
  1175. if (on)
  1176. flags |= flag;
  1177. else
  1178. flags &= ~flag;
  1179. }
  1180. CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, unsigned char flags, EAnimType type):
  1181. CShowableAnim(x,y,name,flags,3,type)
  1182. {
  1183. xOffset = picPos.x;
  1184. yOffset = picPos.y;
  1185. if (picPos.w)
  1186. pos.w = picPos.w;
  1187. if (picPos.h)
  1188. pos.h = picPos.h;
  1189. };
  1190. void CCreatureAnim::loopPreview()
  1191. {
  1192. std::vector<EAnimType> available;
  1193. static const EAnimType previewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
  1194. for (size_t i=0; i<5; i++)
  1195. if (anim.size(previewList[i]))
  1196. available.push_back(previewList[i]);
  1197. size_t rnd = rand()%(available.size()*2);
  1198. if (rnd >= available.size())
  1199. {
  1200. if ( anim.size(MOVING) == 0 )//no moving animation present
  1201. addLast( HOLDING );
  1202. else
  1203. addLast( MOVING ) ;
  1204. }
  1205. else
  1206. addLast(available[rnd]);
  1207. }
  1208. void CCreatureAnim::addLast(EAnimType newType)
  1209. {
  1210. if (type != MOVING && newType == MOVING)//starting moving - play init sequence
  1211. {
  1212. queue.push( MOVE_START );
  1213. }
  1214. else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
  1215. {
  1216. queue.push( MOVE_END );
  1217. }
  1218. if (newType == TURN_L || newType == TURN_R)
  1219. queue.push(newType);
  1220. queue.push(newType);
  1221. }
  1222. void CCreatureAnim::reset()
  1223. {
  1224. //if we are in the middle of rotation - set flag
  1225. if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
  1226. rotate(true);
  1227. if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
  1228. rotate(false);
  1229. while (!queue.empty())
  1230. {
  1231. EAnimType at = queue.front();
  1232. queue.pop();
  1233. if (set(at))
  1234. return;
  1235. }
  1236. if (callback)
  1237. callback();
  1238. while (!queue.empty())
  1239. {
  1240. EAnimType at = queue.front();
  1241. queue.pop();
  1242. if (set(at))
  1243. return;
  1244. }
  1245. set(HOLDING);
  1246. }
  1247. void CCreatureAnim::startPreview()
  1248. {
  1249. callback = boost::bind(&CCreatureAnim::loopPreview,this);
  1250. }
  1251. void CCreatureAnim::clearAndSet(EAnimType type)
  1252. {
  1253. while (!queue.empty())
  1254. queue.pop();
  1255. set(type);
  1256. }