SDL_Extensions.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321
  1. #include "StdInc.h"
  2. #include "SDL_Extensions.h"
  3. #include "SDL_Pixels.h"
  4. #include <SDL_ttf.h>
  5. #include "../CGameInfo.h"
  6. #include "../CMessage.h"
  7. #include "../CDefHandler.h"
  8. #include "../Graphics.h"
  9. /*
  10. * SDL_Extensions.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. SDL_Color Colors::createColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a /*= 0*/)
  19. {
  20. SDL_Color temp = {r, g, b, a};
  21. return temp;
  22. }
  23. const SDL_Color Colors::YELLOW = createColor(229, 215, 123, 0);
  24. const SDL_Color Colors::WHITE = createColor(255, 243, 222, 0);
  25. const SDL_Color Colors::MetallicGold = createColor(173, 142, 66);
  26. const SDL_Color Colors::Maize = createColor(242, 226, 110);
  27. SDL_Surface * CSDL_Ext::newSurface(int w, int h, SDL_Surface * mod) //creates new surface, with flags/format same as in surface given
  28. {
  29. SDL_Surface * ret = SDL_CreateRGBSurface(mod->flags,w,h,mod->format->BitsPerPixel,mod->format->Rmask,mod->format->Gmask,mod->format->Bmask,mod->format->Amask);
  30. if (mod->format->palette)
  31. {
  32. assert(ret->format->palette);
  33. assert(ret->format->palette->ncolors == mod->format->palette->ncolors);
  34. memcpy(ret->format->palette->colors, mod->format->palette->colors, mod->format->palette->ncolors * sizeof(SDL_Color));
  35. }
  36. return ret;
  37. }
  38. SDL_Surface * CSDL_Ext::copySurface(SDL_Surface * mod) //returns copy of given surface
  39. {
  40. //return SDL_DisplayFormat(mod);
  41. return SDL_ConvertSurface(mod, mod->format, mod->flags);
  42. }
  43. template<int bpp>
  44. SDL_Surface * CSDL_Ext::createSurfaceWithBpp(int width, int height)
  45. {
  46. Uint32 rMask = 0, gMask = 0, bMask = 0, aMask = 0;
  47. Channels::px<bpp>::r.set((Uint8*)&rMask, 255);
  48. Channels::px<bpp>::g.set((Uint8*)&gMask, 255);
  49. Channels::px<bpp>::b.set((Uint8*)&bMask, 255);
  50. Channels::px<bpp>::a.set((Uint8*)&aMask, 255);
  51. return SDL_CreateRGBSurface( SDL_SWSURFACE, width, height, bpp * 8, rMask, gMask, bMask, aMask);
  52. }
  53. bool isItIn(const SDL_Rect * rect, int x, int y)
  54. {
  55. return (x>rect->x && x<rect->x+rect->w) && (y>rect->y && y<rect->y+rect->h);
  56. }
  57. void blitAt(SDL_Surface * src, int x, int y, SDL_Surface * dst)
  58. {
  59. if(!dst) dst = screen;
  60. SDL_Rect pom = genRect(src->h,src->w,x,y);
  61. CSDL_Ext::blitSurface(src,NULL,dst,&pom);
  62. }
  63. void blitAt(SDL_Surface * src, const SDL_Rect & pos, SDL_Surface * dst)
  64. {
  65. if (src)
  66. blitAt(src,pos.x,pos.y,dst);
  67. }
  68. SDL_Color genRGB(int r, int g, int b, int a=0)
  69. {
  70. SDL_Color ret;
  71. ret.b=b;
  72. ret.g=g;
  73. ret.r=r;
  74. ret.unused=a;
  75. return ret;
  76. }
  77. void updateRect (SDL_Rect * rect, SDL_Surface * scr)
  78. {
  79. SDL_UpdateRect(scr,rect->x,rect->y,rect->w,rect->h);
  80. }
  81. void printAtMiddleWB(const std::string & text, int x, int y, TTF_Font * font, int charpr, SDL_Color kolor, SDL_Surface * dst)
  82. {
  83. std::vector<std::string> ws = CMessage::breakText(text,charpr);
  84. std::vector<SDL_Surface*> wesu;
  85. wesu.resize(ws.size());
  86. for (size_t i=0; i < wesu.size(); ++i)
  87. {
  88. wesu[i]=TTF_RenderText_Blended(font,ws[i].c_str(),kolor);
  89. }
  90. int tox=0, toy=0;
  91. for (size_t i=0; i < wesu.size(); ++i)
  92. {
  93. toy+=wesu[i]->h;
  94. if (tox < wesu[i]->w)
  95. tox=wesu[i]->w;
  96. }
  97. int evx, evy = y - (toy/2);
  98. for (size_t i=0; i < wesu.size(); ++i)
  99. {
  100. evx = (x - (tox/2)) + ((tox-wesu[i]->w)/2);
  101. blitAt(wesu[i],evx,evy,dst);
  102. evy+=wesu[i]->h;
  103. }
  104. for (size_t i=0; i < wesu.size(); ++i)
  105. SDL_FreeSurface(wesu[i]);
  106. }
  107. void printAtWB(const std::string & text, int x, int y, TTF_Font * font, int charpr, SDL_Color kolor, SDL_Surface * dst)
  108. {
  109. std::vector<std::string> ws = CMessage::breakText(text,charpr);
  110. std::vector<SDL_Surface*> wesu;
  111. wesu.resize(ws.size());
  112. for (size_t i=0; i < wesu.size(); ++i)
  113. wesu[i]=TTF_RenderText_Blended(font,ws[i].c_str(),kolor);
  114. int evy = y;
  115. for (size_t i=0; i < wesu.size(); ++i)
  116. {
  117. blitAt(wesu[i],x,evy,dst);
  118. evy+=wesu[i]->h;
  119. }
  120. for (size_t i=0; i < wesu.size(); ++i)
  121. SDL_FreeSurface(wesu[i]);
  122. }
  123. void CSDL_Ext::printAtWB(const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor, SDL_Surface * dst)
  124. {
  125. if (graphics->fontsTrueType[font])
  126. {
  127. printAtWB(text,x, y, graphics->fontsTrueType[font], charpr, kolor, dst);
  128. return;
  129. }
  130. const Font *f = graphics->fonts[font];
  131. std::vector<std::string> ws = CMessage::breakText(text,charpr);
  132. int cury = y;
  133. for (size_t i=0; i < ws.size(); ++i)
  134. {
  135. printAt(ws[i], x, cury, font, kolor, dst);
  136. cury += f->height;
  137. }
  138. }
  139. void CSDL_Ext::printAtMiddleWB( const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor/*=Colors::YELLOW*/, SDL_Surface * dst/*=screen*/ )
  140. {
  141. if (graphics->fontsTrueType[font])
  142. {
  143. printAtMiddleWB(text,x, y, graphics->fontsTrueType[font], charpr, kolor, dst);
  144. return;
  145. }
  146. const Font *f = graphics->fonts[font];
  147. std::vector<std::string> ws = CMessage::breakText(text,charpr);
  148. int totalHeight = ws.size() * f->height;
  149. int cury = y - totalHeight/2;
  150. for (size_t i=0; i < ws.size(); ++i)
  151. {
  152. printAt(ws[i], x - f->getWidth(ws[i].c_str())/2, cury, font, kolor, dst);
  153. cury += f->height;
  154. }
  155. }
  156. void printAtMiddle(const std::string & text, int x, int y, TTF_Font * font, SDL_Color kolor, SDL_Surface * dst, ui8 quality=2)
  157. {
  158. if(text.length()==0) return;
  159. SDL_Surface * temp;
  160. switch (quality)
  161. {
  162. case 0:
  163. temp = TTF_RenderText_Solid(font,text.c_str(),kolor);
  164. break;
  165. case 1:
  166. SDL_Color tem;
  167. tem.b = 0xff-kolor.b;
  168. tem.g = 0xff-kolor.g;
  169. tem.r = 0xff-kolor.r;
  170. tem.unused = 0xff-kolor.unused;
  171. temp = TTF_RenderText_Shaded(font,text.c_str(),kolor,tem);
  172. break;
  173. case 2:
  174. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  175. break;
  176. default:
  177. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  178. break;
  179. }
  180. SDL_Rect dstRect = genRect(temp->h, temp->w, x-(temp->w/2), y-(temp->h/2));
  181. CSDL_Ext::blitSurface(temp, NULL, dst, &dstRect);
  182. SDL_FreeSurface(temp);
  183. }
  184. void CSDL_Ext::printAtMiddle( const std::string & text, int x, int y, EFonts font, SDL_Color kolor/*=Colors::WHITE*/, SDL_Surface * dst/*=screen*/ )
  185. {
  186. if (graphics->fontsTrueType[font])
  187. {
  188. printAtMiddle(text,x, y, graphics->fontsTrueType[font], kolor, dst);
  189. return;
  190. }
  191. const Font *f = graphics->fonts[font];
  192. int nx = x - f->getWidth(text.c_str())/2,
  193. ny = y - f->height/2;
  194. printAt(text, nx, ny, font, kolor, dst);
  195. }
  196. void printAt(const std::string & text, int x, int y, TTF_Font * font, SDL_Color kolor, SDL_Surface * dst, ui8 quality=2, bool refresh=false)
  197. {
  198. if (text.length()==0)
  199. return;
  200. SDL_Surface * temp;
  201. switch (quality)
  202. {
  203. case 0:
  204. temp = TTF_RenderText_Solid(font,text.c_str(),kolor);
  205. break;
  206. case 1:
  207. SDL_Color tem;
  208. tem.b = 0xff-kolor.b;
  209. tem.g = 0xff-kolor.g;
  210. tem.r = 0xff-kolor.r;
  211. tem.unused = 0xff-kolor.unused;
  212. temp = TTF_RenderText_Shaded(font,text.c_str(),kolor,tem);
  213. break;
  214. case 2:
  215. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  216. break;
  217. default:
  218. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  219. break;
  220. }
  221. SDL_Rect dstRect = genRect(temp->h,temp->w,x,y);
  222. CSDL_Ext::blitSurface(temp,NULL,dst,&dstRect);
  223. if(refresh)
  224. SDL_UpdateRect(dst,x,y,temp->w,temp->h);
  225. SDL_FreeSurface(temp);
  226. }
  227. void CSDL_Ext::printAt( const std::string & text, int dstX, int dstY, EFonts font, SDL_Color color, SDL_Surface * dst)
  228. {
  229. if(!text.size())
  230. return;
  231. if (graphics->fontsTrueType[font])
  232. {
  233. printAt(text,dstX, dstY, graphics->fontsTrueType[font], color, dst);
  234. return;
  235. }
  236. assert(dst);
  237. assert(font < Graphics::FONTS_NUMBER);
  238. Rect clipRect;
  239. SDL_GetClipRect(dst, &clipRect);
  240. const Font *f = graphics->fonts[font];
  241. const Uint8 bpp = dst->format->BytesPerPixel;
  242. TColorPutter colorPutter = getPutterFor(dst, 0);
  243. //if text is in {} braces, we'll ommit them
  244. const int textBegin = (text[0] == '{' ? 1 : 0);
  245. const int textEnd = (text[text.size()-1] == '}' ? text.size()-1 : text.size());
  246. SDL_LockSurface(dst);
  247. // for each symbol
  248. for(int index = textBegin; index < textEnd; index++)
  249. {
  250. const ui8 symbol = text[index];
  251. dstX += f->chars[symbol].leftOffset;
  252. int lineBegin = std::max<int>(0, clipRect.y - dstY);
  253. int lineEnd = std::min<int>(f->height, clipRect.y + clipRect.h - dstY - 1);
  254. int rowBegin = std::max(0, clipRect.x - dstX);
  255. int rowEnd = std::min(f->chars[symbol].width, clipRect.x + clipRect.w - dstX - 1);
  256. //for each line in symbol
  257. for(int dy = lineBegin; dy <lineEnd; dy++)
  258. {
  259. Uint8 *dstLine = (Uint8*)dst->pixels;
  260. Uint8 *srcLine = f->chars[symbol].pixels;
  261. dstLine += (dstY+dy) * dst->pitch + dstX * bpp;
  262. srcLine += dy * f->chars[symbol].width;
  263. //for each column in line
  264. for(int dx = rowBegin; dx < rowEnd; dx++)
  265. {
  266. Uint8* dstPixel = dstLine + dx*bpp;
  267. switch(*(srcLine + dx))
  268. {
  269. case 1: //black "shadow"
  270. memset(dstPixel, 0, bpp);
  271. break;
  272. case 255: //text colour
  273. colorPutter(dstPixel, color.r, color.g, color.b);
  274. break;
  275. }
  276. }
  277. }
  278. dstX += f->chars[symbol].width;
  279. dstX += f->chars[symbol].rightOffset;
  280. }
  281. SDL_UnlockSurface(dst);
  282. }
  283. void printTo(const std::string & text, int x, int y, TTF_Font * font, SDL_Color kolor, SDL_Surface * dst, ui8 quality=2)
  284. {
  285. if (text.length()==0)
  286. return;
  287. SDL_Surface * temp;
  288. switch (quality)
  289. {
  290. case 0:
  291. temp = TTF_RenderText_Solid(font,text.c_str(),kolor);
  292. break;
  293. case 1:
  294. SDL_Color tem;
  295. tem.b = 0xff-kolor.b;
  296. tem.g = 0xff-kolor.g;
  297. tem.r = 0xff-kolor.r;
  298. tem.unused = 0xff-kolor.unused;
  299. temp = TTF_RenderText_Shaded(font,text.c_str(),kolor,tem);
  300. break;
  301. case 2:
  302. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  303. break;
  304. default:
  305. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  306. break;
  307. }
  308. SDL_Rect dstRect = genRect(temp->h,temp->w,x-temp->w,y-temp->h);
  309. CSDL_Ext::blitSurface(temp,NULL,dst,&dstRect);
  310. SDL_UpdateRect(dst,x-temp->w,y-temp->h,temp->w,temp->h);
  311. SDL_FreeSurface(temp);
  312. }
  313. void CSDL_Ext::printTo( const std::string & text, int x, int y, EFonts font, SDL_Color kolor/*=Colors::WHITE*/, SDL_Surface * dst/*=screen*/ )
  314. {
  315. if (graphics->fontsTrueType[font])
  316. {
  317. printTo(text,x, y, graphics->fontsTrueType[font], kolor, dst);
  318. return;
  319. }
  320. const Font *f = graphics->fonts[font];
  321. printAt(text, x - f->getWidth(text.c_str()), y - f->height, font, kolor, dst);
  322. }
  323. void printToWR(const std::string & text, int x, int y, TTF_Font * font, SDL_Color kolor, SDL_Surface * dst, ui8 quality=2)
  324. {
  325. if (text.length()==0)
  326. return;
  327. SDL_Surface * temp;
  328. switch (quality)
  329. {
  330. case 0:
  331. temp = TTF_RenderText_Solid(font,text.c_str(),kolor);
  332. break;
  333. case 1:
  334. SDL_Color tem;
  335. tem.b = 0xff-kolor.b;
  336. tem.g = 0xff-kolor.g;
  337. tem.r = 0xff-kolor.r;
  338. tem.unused = 0xff-kolor.unused;
  339. temp = TTF_RenderText_Shaded(font,text.c_str(),kolor,tem);
  340. break;
  341. case 2:
  342. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  343. break;
  344. default:
  345. temp = TTF_RenderText_Blended(font,text.c_str(),kolor);
  346. break;
  347. }
  348. SDL_Rect dstRect = genRect(temp->h,temp->w,x-temp->w,y-temp->h);
  349. CSDL_Ext::blitSurface(temp,NULL,dst,&dstRect);
  350. SDL_FreeSurface(temp);
  351. }
  352. // Vertical flip
  353. SDL_Surface * CSDL_Ext::rotate01(SDL_Surface * toRot)
  354. {
  355. SDL_Surface * ret = SDL_ConvertSurface(toRot, toRot->format, toRot->flags);
  356. const int bpl = ret->pitch;
  357. const int bpp = ret->format->BytesPerPixel;
  358. for(int i=0; i<ret->h; i++) {
  359. char *src = (char *)toRot->pixels + i*bpl;
  360. char *dst = (char *)ret->pixels + i*bpl;
  361. for(int j=0; j<ret->w; j++) {
  362. for (int k=0; k<bpp; k++) {
  363. dst[j*bpp + k] = src[(ret->w-j-1)*bpp + k];
  364. }
  365. }
  366. }
  367. return ret;
  368. }
  369. // Horizontal flip
  370. SDL_Surface * CSDL_Ext::hFlip(SDL_Surface * toRot)
  371. {
  372. SDL_Surface * ret = SDL_ConvertSurface(toRot, toRot->format, toRot->flags);
  373. int bpl = ret->pitch;
  374. for(int i=0; i<ret->h; i++) {
  375. memcpy((char *)ret->pixels + i*bpl, (char *)toRot->pixels + (ret->h-i-1)*bpl, bpl);
  376. }
  377. return ret;
  378. };
  379. ///**************/
  380. ///Rotates toRot surface by 90 degrees left
  381. ///**************/
  382. SDL_Surface * CSDL_Ext::rotate02(SDL_Surface * toRot)
  383. {
  384. SDL_Surface * ret = SDL_ConvertSurface(toRot, toRot->format, toRot->flags);
  385. //SDL_SetColorKey(ret, SDL_SRCCOLORKEY, toRot->format->colorkey);
  386. for(int i=0; i<ret->w; ++i)
  387. {
  388. for(int j=0; j<ret->h; ++j)
  389. {
  390. {
  391. Uint8 *p = (Uint8 *)toRot->pixels + i * toRot->pitch + j * toRot->format->BytesPerPixel;
  392. SDL_PutPixelWithoutRefresh(ret, i, j, p[2], p[1], p[0]);
  393. }
  394. }
  395. }
  396. return ret;
  397. }
  398. ///*************/
  399. ///Rotates toRot surface by 180 degrees
  400. ///*************/
  401. SDL_Surface * CSDL_Ext::rotate03(SDL_Surface * toRot)
  402. {
  403. SDL_Surface * ret = SDL_ConvertSurface(toRot, toRot->format, toRot->flags);
  404. if(ret->format->BytesPerPixel!=1)
  405. {
  406. for(int i=0; i<ret->w; ++i)
  407. {
  408. for(int j=0; j<ret->h; ++j)
  409. {
  410. {
  411. Uint8 *p = (Uint8 *)toRot->pixels + (ret->h - j - 1) * toRot->pitch + (ret->w - i - 1) * toRot->format->BytesPerPixel+2;
  412. SDL_PutPixelWithoutRefresh(ret, i, j, p[2], p[1], p[0], 0);
  413. }
  414. }
  415. }
  416. }
  417. else
  418. {
  419. for(int i=0; i<ret->w; ++i)
  420. {
  421. for(int j=0; j<ret->h; ++j)
  422. {
  423. Uint8 *p = (Uint8 *)toRot->pixels + (ret->h - j - 1) * toRot->pitch + (ret->w - i - 1) * toRot->format->BytesPerPixel;
  424. (*((Uint8*)ret->pixels + j*ret->pitch + i*ret->format->BytesPerPixel)) = *p;
  425. }
  426. }
  427. }
  428. return ret;
  429. }
  430. Uint32 CSDL_Ext::SDL_GetPixel(SDL_Surface *surface, const int & x, const int & y, bool colorByte)
  431. {
  432. int bpp = surface->format->BytesPerPixel;
  433. /* Here p is the address to the pixel we want to retrieve */
  434. Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
  435. switch(bpp)
  436. {
  437. case 1:
  438. if(colorByte)
  439. {
  440. return colorToUint32(surface->format->palette->colors+(*p));
  441. }
  442. else
  443. return *p;
  444. case 2:
  445. return *(Uint16 *)p;
  446. case 3:
  447. return p[0] | p[1] << 8 | p[2] << 16;
  448. case 4:
  449. return *(Uint32 *)p;
  450. default:
  451. return 0; // shouldn't happen, but avoids warnings
  452. }
  453. }
  454. void CSDL_Ext::alphaTransform(SDL_Surface *src)
  455. {
  456. //NOTE: colors #7 & #8 used in some of WoG objects. Don't know how they're handled by H3
  457. assert(src->format->BitsPerPixel == 8);
  458. SDL_Color colors[] = {{0,0,0,0}, {0,0,0,32}, {0,0,0,64}, {0,0,0,128}, {0,0,0,128},
  459. {255,255,255,0}, {255,255,255,0}, {255,255,255,0}, {0,0,0,192}, {0,0,0,192}};
  460. SDL_SetColors(src, colors, 0, ARRAY_COUNT(colors));
  461. SDL_SetColorKey(src, SDL_SRCCOLORKEY, SDL_MapRGBA(src->format, 0, 0, 0, 255));
  462. }
  463. static void prepareOutRect(SDL_Rect *src, SDL_Rect *dst, const SDL_Rect & clip_rect)
  464. {
  465. const int xoffset = std::max(clip_rect.x - dst->x, 0),
  466. yoffset = std::max(clip_rect.y - dst->y, 0);
  467. src->x += xoffset;
  468. src->y += yoffset;
  469. dst->x += xoffset;
  470. dst->y += yoffset;
  471. src->w = dst->w = std::max(0,std::min(dst->w - xoffset, clip_rect.x + clip_rect.w - dst->x));
  472. src->h = dst->h = std::max(0,std::min(dst->h - yoffset, clip_rect.y + clip_rect.h - dst->y));
  473. }
  474. template<int bpp>
  475. void CSDL_Ext::blitWithRotateClip(SDL_Surface *src,SDL_Rect * srcRect, SDL_Surface * dst, SDL_Rect * dstRect, ui8 rotation)//srcRect is not used, works with 8bpp sources and 24bpp dests
  476. {
  477. static void (*blitWithRotate[])(const SDL_Surface *, const SDL_Rect *, SDL_Surface *, const SDL_Rect *) = {blitWithRotate1<bpp>, blitWithRotate2<bpp>, blitWithRotate3<bpp>};
  478. if(!rotation)
  479. {
  480. CSDL_Ext::blitSurface(src, srcRect, dst, dstRect);
  481. }
  482. else
  483. {
  484. prepareOutRect(srcRect, dstRect, dst->clip_rect);
  485. blitWithRotate[rotation-1](src, srcRect, dst, dstRect);
  486. }
  487. }
  488. template<int bpp>
  489. void CSDL_Ext::blitWithRotateClipVal( SDL_Surface *src,SDL_Rect srcRect, SDL_Surface * dst, SDL_Rect dstRect, ui8 rotation )
  490. {
  491. blitWithRotateClip<bpp>(src, &srcRect, dst, &dstRect, rotation);
  492. }
  493. template<int bpp>
  494. void CSDL_Ext::blitWithRotateClipWithAlpha(SDL_Surface *src,SDL_Rect * srcRect, SDL_Surface * dst, SDL_Rect * dstRect, ui8 rotation)//srcRect is not used, works with 8bpp sources and 24bpp dests
  495. {
  496. static void (*blitWithRotate[])(const SDL_Surface *, const SDL_Rect *, SDL_Surface *, const SDL_Rect *) = {blitWithRotate1WithAlpha<bpp>, blitWithRotate2WithAlpha<bpp>, blitWithRotate3WithAlpha<bpp>};
  497. if(!rotation)
  498. {
  499. blit8bppAlphaTo24bpp(src, srcRect, dst, dstRect);
  500. }
  501. else
  502. {
  503. prepareOutRect(srcRect, dstRect, dst->clip_rect);
  504. blitWithRotate[rotation-1](src, srcRect, dst, dstRect);
  505. }
  506. }
  507. template<int bpp>
  508. void CSDL_Ext::blitWithRotateClipValWithAlpha( SDL_Surface *src,SDL_Rect srcRect, SDL_Surface * dst, SDL_Rect dstRect, ui8 rotation )
  509. {
  510. blitWithRotateClipWithAlpha<bpp>(src, &srcRect, dst, &dstRect, rotation);
  511. }
  512. template<int bpp>
  513. void CSDL_Ext::blitWithRotate1(const SDL_Surface *src, const SDL_Rect * srcRect, SDL_Surface * dst, const SDL_Rect * dstRect)//srcRect is not used, works with 8bpp sources and 24/32 bpp dests
  514. {
  515. Uint8 *sp = getPxPtr(src, src->w - srcRect->w - srcRect->x, srcRect->y);
  516. Uint8 *dporg = (Uint8 *)dst->pixels + dstRect->y*dst->pitch + (dstRect->x+dstRect->w)*bpp;
  517. const SDL_Color * const colors = src->format->palette->colors;
  518. for(int i=dstRect->h; i>0; i--, dporg += dst->pitch)
  519. {
  520. Uint8 *dp = dporg;
  521. for(int j=dstRect->w; j>0; j--, sp++)
  522. ColorPutter<bpp, -1>::PutColor(dp, colors[*sp]);
  523. sp += src->w - dstRect->w;
  524. }
  525. }
  526. template<int bpp>
  527. void CSDL_Ext::blitWithRotate2(const SDL_Surface *src, const SDL_Rect * srcRect, SDL_Surface * dst, const SDL_Rect * dstRect)//srcRect is not used, works with 8bpp sources and 24/32 bpp dests
  528. {
  529. Uint8 *sp = getPxPtr(src, srcRect->x, src->h - srcRect->h - srcRect->y);
  530. Uint8 *dporg = (Uint8 *)dst->pixels + (dstRect->y + dstRect->h - 1)*dst->pitch + dstRect->x*bpp;
  531. const SDL_Color * const colors = src->format->palette->colors;
  532. for(int i=dstRect->h; i>0; i--, dporg -= dst->pitch)
  533. {
  534. Uint8 *dp = dporg;
  535. for(int j=dstRect->w; j>0; j--, sp++)
  536. ColorPutter<bpp, 1>::PutColor(dp, colors[*sp]);
  537. sp += src->w - dstRect->w;
  538. }
  539. }
  540. template<int bpp>
  541. void CSDL_Ext::blitWithRotate3(const SDL_Surface *src, const SDL_Rect * srcRect, SDL_Surface * dst, const SDL_Rect * dstRect)//srcRect is not used, works with 8bpp sources and 24/32 bpp dests
  542. {
  543. Uint8 *sp = (Uint8 *)src->pixels + (src->h - srcRect->h - srcRect->y)*src->pitch + (src->w - srcRect->w - srcRect->x);
  544. Uint8 *dporg = (Uint8 *)dst->pixels +(dstRect->y + dstRect->h - 1)*dst->pitch + (dstRect->x+dstRect->w)*bpp;
  545. const SDL_Color * const colors = src->format->palette->colors;
  546. for(int i=dstRect->h; i>0; i--, dporg -= dst->pitch)
  547. {
  548. Uint8 *dp = dporg;
  549. for(int j=dstRect->w; j>0; j--, sp++)
  550. ColorPutter<bpp, -1>::PutColor(dp, colors[*sp]);
  551. sp += src->w - dstRect->w;
  552. }
  553. }
  554. template<int bpp>
  555. void CSDL_Ext::blitWithRotate1WithAlpha(const SDL_Surface *src, const SDL_Rect * srcRect, SDL_Surface * dst, const SDL_Rect * dstRect)//srcRect is not used, works with 8bpp sources and 24/32 bpp dests
  556. {
  557. Uint8 *sp = (Uint8 *)src->pixels + srcRect->y*src->pitch + (src->w - srcRect->w - srcRect->x);
  558. Uint8 *dporg = (Uint8 *)dst->pixels + dstRect->y*dst->pitch + (dstRect->x+dstRect->w)*bpp;
  559. const SDL_Color * const colors = src->format->palette->colors;
  560. for(int i=dstRect->h; i>0; i--, dporg += dst->pitch)
  561. {
  562. Uint8 *dp = dporg;
  563. for(int j=dstRect->w; j>0; j--, sp++)
  564. {
  565. if(*sp)
  566. ColorPutter<bpp, -1>::PutColor(dp, colors[*sp]);
  567. else
  568. dp -= bpp;
  569. }
  570. sp += src->w - dstRect->w;
  571. }
  572. }
  573. template<int bpp>
  574. void CSDL_Ext::blitWithRotate2WithAlpha(const SDL_Surface *src, const SDL_Rect * srcRect, SDL_Surface * dst, const SDL_Rect * dstRect)//srcRect is not used, works with 8bpp sources and 24/32 bpp dests
  575. {
  576. Uint8 *sp = (Uint8 *)src->pixels + (src->h - srcRect->h - srcRect->y)*src->pitch + srcRect->x;
  577. Uint8 *dporg = (Uint8 *)dst->pixels + (dstRect->y + dstRect->h - 1)*dst->pitch + dstRect->x*bpp;
  578. const SDL_Color * const colors = src->format->palette->colors;
  579. for(int i=dstRect->h; i>0; i--, dporg -= dst->pitch)
  580. {
  581. Uint8 *dp = dporg;
  582. for(int j=dstRect->w; j>0; j--, sp++)
  583. {
  584. if(*sp)
  585. ColorPutter<bpp, 1>::PutColor(dp, colors[*sp]);
  586. else
  587. dp += bpp;
  588. }
  589. sp += src->w - dstRect->w;
  590. }
  591. }
  592. template<int bpp>
  593. void CSDL_Ext::blitWithRotate3WithAlpha(const SDL_Surface *src, const SDL_Rect * srcRect, SDL_Surface * dst, const SDL_Rect * dstRect)//srcRect is not used, works with 8bpp sources and 24/32 bpp dests
  594. {
  595. Uint8 *sp = (Uint8 *)src->pixels + (src->h - srcRect->h - srcRect->y)*src->pitch + (src->w - srcRect->w - srcRect->x);
  596. Uint8 *dporg = (Uint8 *)dst->pixels +(dstRect->y + dstRect->h - 1)*dst->pitch + (dstRect->x+dstRect->w)*bpp;
  597. const SDL_Color * const colors = src->format->palette->colors;
  598. for(int i=dstRect->h; i>0; i--, dporg -= dst->pitch)
  599. {
  600. Uint8 *dp = dporg;
  601. for(int j=dstRect->w; j>0; j--, sp++)
  602. {
  603. if(*sp)
  604. ColorPutter<bpp, -1>::PutColor(dp, colors[*sp]);
  605. else
  606. dp -= bpp;
  607. }
  608. sp += src->w - dstRect->w;
  609. }
  610. }
  611. template<int bpp>
  612. int CSDL_Ext::blit8bppAlphaTo24bppT(const SDL_Surface * src, const SDL_Rect * srcRect, SDL_Surface * dst, SDL_Rect * dstRect)
  613. {
  614. if (src && src->format->BytesPerPixel==1 && dst && (bpp==3 || bpp==4 || bpp==2)) //everything's ok
  615. {
  616. SDL_Rect fulldst;
  617. int srcx, srcy, w, h;
  618. /* Make sure the surfaces aren't locked */
  619. if ( ! src || ! dst )
  620. {
  621. SDL_SetError("SDL_UpperBlit: passed a NULL surface");
  622. return -1;
  623. }
  624. if ( src->locked || dst->locked )
  625. {
  626. SDL_SetError("Surfaces must not be locked during blit");
  627. return -1;
  628. }
  629. /* If the destination rectangle is NULL, use the entire dest surface */
  630. if ( dstRect == NULL )
  631. {
  632. fulldst.x = fulldst.y = 0;
  633. dstRect = &fulldst;
  634. }
  635. /* clip the source rectangle to the source surface */
  636. if(srcRect)
  637. {
  638. int maxw, maxh;
  639. srcx = srcRect->x;
  640. w = srcRect->w;
  641. if(srcx < 0)
  642. {
  643. w += srcx;
  644. dstRect->x -= srcx;
  645. srcx = 0;
  646. }
  647. maxw = src->w - srcx;
  648. if(maxw < w)
  649. w = maxw;
  650. srcy = srcRect->y;
  651. h = srcRect->h;
  652. if(srcy < 0)
  653. {
  654. h += srcy;
  655. dstRect->y -= srcy;
  656. srcy = 0;
  657. }
  658. maxh = src->h - srcy;
  659. if(maxh < h)
  660. h = maxh;
  661. }
  662. else
  663. {
  664. srcx = srcy = 0;
  665. w = src->w;
  666. h = src->h;
  667. }
  668. /* clip the destination rectangle against the clip rectangle */
  669. {
  670. SDL_Rect *clip = &dst->clip_rect;
  671. int dx, dy;
  672. dx = clip->x - dstRect->x;
  673. if(dx > 0)
  674. {
  675. w -= dx;
  676. dstRect->x += dx;
  677. srcx += dx;
  678. }
  679. dx = dstRect->x + w - clip->x - clip->w;
  680. if(dx > 0)
  681. w -= dx;
  682. dy = clip->y - dstRect->y;
  683. if(dy > 0)
  684. {
  685. h -= dy;
  686. dstRect->y += dy;
  687. srcy += dy;
  688. }
  689. dy = dstRect->y + h - clip->y - clip->h;
  690. if(dy > 0)
  691. h -= dy;
  692. }
  693. if(w > 0 && h > 0)
  694. {
  695. dstRect->w = w;
  696. dstRect->h = h;
  697. if(SDL_LockSurface(dst))
  698. return -1; //if we cannot lock the surface
  699. const SDL_Color *colors = src->format->palette->colors;
  700. Uint8 *colory = (Uint8*)src->pixels + srcy*src->pitch + srcx;
  701. Uint8 *py = (Uint8*)dst->pixels + dstRect->y*dst->pitch + dstRect->x*bpp;
  702. for(int y=h; y; y--, colory+=src->pitch, py+=dst->pitch)
  703. {
  704. Uint8 *color = colory;
  705. Uint8 *p = py;
  706. for(int x = w; x; x--)
  707. {
  708. const SDL_Color &tbc = colors[*color++]; //color to blit
  709. ColorPutter<bpp, +1>::PutColorAlphaSwitch(p, tbc.r, tbc.g, tbc.b, tbc.unused);
  710. }
  711. }
  712. SDL_UnlockSurface(dst);
  713. }
  714. }
  715. return 0;
  716. }
  717. int CSDL_Ext::blit8bppAlphaTo24bpp(const SDL_Surface * src, const SDL_Rect * srcRect, SDL_Surface * dst, SDL_Rect * dstRect)
  718. {
  719. switch(dst->format->BytesPerPixel)
  720. {
  721. case 2: return blit8bppAlphaTo24bppT<2>(src, srcRect, dst, dstRect);
  722. case 3: return blit8bppAlphaTo24bppT<3>(src, srcRect, dst, dstRect);
  723. case 4: return blit8bppAlphaTo24bppT<4>(src, srcRect, dst, dstRect);
  724. default:
  725. tlog1 << (int)dst->format->BitsPerPixel << " bpp is not supported!!!\n";
  726. return -1;
  727. }
  728. }
  729. Uint32 CSDL_Ext::colorToUint32(const SDL_Color * color)
  730. {
  731. Uint32 ret = 0;
  732. ret+=color->unused;
  733. ret<<=8; //*=256
  734. ret+=color->b;
  735. ret<<=8; //*=256
  736. ret+=color->g;
  737. ret<<=8; //*=256
  738. ret+=color->r;
  739. return ret;
  740. }
  741. void CSDL_Ext::update(SDL_Surface * what)
  742. {
  743. if(what)
  744. SDL_UpdateRect(what, 0, 0, what->w, what->h);
  745. }
  746. void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const int3 &color)
  747. {
  748. for(int i = 0; i < w; i++)
  749. {
  750. SDL_PutPixelWithoutRefreshIfInSurf(sur,x+i,y,color.x,color.y,color.z);
  751. SDL_PutPixelWithoutRefreshIfInSurf(sur,x+i,y+h-1,color.x,color.y,color.z);
  752. }
  753. for(int i = 0; i < h; i++)
  754. {
  755. SDL_PutPixelWithoutRefreshIfInSurf(sur,x,y+i,color.x,color.y,color.z);
  756. SDL_PutPixelWithoutRefreshIfInSurf(sur,x+w-1,y+i,color.x,color.y,color.z);
  757. }
  758. }
  759. void CSDL_Ext::drawBorder( SDL_Surface * sur, const SDL_Rect &r, const int3 &color )
  760. {
  761. drawBorder(sur, r.x, r.y, r.w, r.h, color);
  762. }
  763. void CSDL_Ext::drawDashedBorder(SDL_Surface * sur, const Rect &r, const int3 &color)
  764. {
  765. const int y1 = r.y, y2 = r.y + r.h-1;
  766. for (int i=0; i<r.w; i++)
  767. {
  768. const int x = r.x + i;
  769. if (i%4 || (i==0))
  770. {
  771. SDL_PutPixelWithoutRefreshIfInSurf(sur, x, y1, color.x, color.y, color.z);
  772. SDL_PutPixelWithoutRefreshIfInSurf(sur, x, y2, color.x, color.y, color.z);
  773. }
  774. }
  775. const int x1 = r.x, x2 = r.x + r.w-1;
  776. for (int i=0; i<r.h; i++)
  777. {
  778. const int y = r.y + i;
  779. if ((i%4) || (i==0))
  780. {
  781. SDL_PutPixelWithoutRefreshIfInSurf(sur, x1, y, color.x, color.y, color.z);
  782. SDL_PutPixelWithoutRefreshIfInSurf(sur, x2, y, color.x, color.y, color.z);
  783. }
  784. }
  785. }
  786. void CSDL_Ext::setPlayerColor(SDL_Surface * sur, ui8 player)
  787. {
  788. if(player==254)
  789. return;
  790. if(sur->format->BitsPerPixel==8)
  791. {
  792. SDL_Color *color = (player == 255
  793. ? graphics->neutralColor
  794. : &graphics->playerColors[player]);
  795. SDL_SetColors(sur, color, 5, 1);
  796. }
  797. else
  798. tlog3 << "Warning, setPlayerColor called on not 8bpp surface!\n";
  799. }
  800. TColorPutter CSDL_Ext::getPutterFor(SDL_Surface * const &dest, int incrementing)
  801. {
  802. #define CASE_BPP(BytesPerPixel) \
  803. case BytesPerPixel: \
  804. if(incrementing > 0) \
  805. return ColorPutter<BytesPerPixel, 1>::PutColor; \
  806. else if(incrementing == 0) \
  807. return ColorPutter<BytesPerPixel, 0>::PutColor; \
  808. else \
  809. return ColorPutter<BytesPerPixel, -1>::PutColor;\
  810. break;
  811. switch(dest->format->BytesPerPixel)
  812. {
  813. CASE_BPP(2)
  814. CASE_BPP(3)
  815. CASE_BPP(4)
  816. default:
  817. tlog1 << (int)dest->format->BitsPerPixel << "bpp is not supported!\n";
  818. return NULL;
  819. }
  820. }
  821. TColorPutterAlpha CSDL_Ext::getPutterAlphaFor(SDL_Surface * const &dest, int incrementing)
  822. {
  823. switch(dest->format->BytesPerPixel)
  824. {
  825. CASE_BPP(2)
  826. CASE_BPP(3)
  827. CASE_BPP(4)
  828. default:
  829. tlog1 << (int)dest->format->BitsPerPixel << "bpp is not supported!\n";
  830. return NULL;
  831. }
  832. #undef CASE_BPP
  833. }
  834. Uint8 * CSDL_Ext::getPxPtr(const SDL_Surface * const &srf, const int x, const int y)
  835. {
  836. return (Uint8 *)srf->pixels + y * srf->pitch + x * srf->format->BytesPerPixel;
  837. }
  838. std::string CSDL_Ext::processStr(std::string str, std::vector<std::string> & tor)
  839. {
  840. for (size_t i=0; (i<tor.size())&&(boost::find_first(str,"%s")); ++i)
  841. {
  842. boost::replace_first(str,"%s",tor[i]);
  843. }
  844. return str;
  845. }
  846. bool CSDL_Ext::isTransparent( SDL_Surface * srf, int x, int y )
  847. {
  848. if (x < 0 || y < 0 || x >= srf->w || y >= srf->h)
  849. return true;
  850. if(srf->format->BytesPerPixel == 1)
  851. {
  852. return ((ui8*)srf->pixels)[x + srf->pitch * y] == 0;
  853. }
  854. else
  855. {
  856. assert(!"isTransparent called with non-8bpp surface!");
  857. }
  858. return false;
  859. }
  860. void CSDL_Ext::VflipSurf(SDL_Surface * surf)
  861. {
  862. char buf[4]; //buffer
  863. int bpp = surf->format->BytesPerPixel;
  864. for (int y=0; y<surf->h; ++y)
  865. {
  866. char * base = (char*)surf->pixels + y * surf->pitch;
  867. for (int x=0; x<surf->w/2; ++x)
  868. {
  869. memcpy(buf, base + x * bpp, bpp);
  870. memcpy(base + x * bpp, base + (surf->w - x - 1) * bpp, bpp);
  871. memcpy(base + (surf->w - x - 1) * bpp, buf, bpp);
  872. }
  873. }
  874. }
  875. void CSDL_Ext::SDL_PutPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const int & y, const Uint8 & R, const Uint8 & G, const Uint8 & B, Uint8 A /*= 255*/)
  876. {
  877. Uint8 *p = getPxPtr(ekran, x, y);
  878. getPutterFor(ekran, false)(p, R, G, B);
  879. switch(ekran->format->BytesPerPixel)
  880. {
  881. case 2: Channels::px<2>::a.set(p, A); break;
  882. case 3: Channels::px<3>::a.set(p, A); break;
  883. case 4: Channels::px<4>::a.set(p, A); break;
  884. }
  885. }
  886. void CSDL_Ext::SDL_PutPixelWithoutRefreshIfInSurf(SDL_Surface *ekran, const int & x, const int & y, const Uint8 & R, const Uint8 & G, const Uint8 & B, Uint8 A /*= 255*/)
  887. {
  888. const SDL_Rect & rect = ekran->clip_rect;
  889. if(x >= rect.x && x < rect.w + rect.x
  890. && y >= rect.y && y < rect.h + rect.y)
  891. SDL_PutPixelWithoutRefresh(ekran, x, y, R, G, B, A);
  892. }
  893. BlitterWithRotationVal CSDL_Ext::getBlitterWithRotation(SDL_Surface *dest)
  894. {
  895. switch(dest->format->BytesPerPixel)
  896. {
  897. case 2: return blitWithRotateClipVal<2>;
  898. case 3: return blitWithRotateClipVal<3>;
  899. case 4: return blitWithRotateClipVal<4>;
  900. default:
  901. tlog1 << (int)dest->format->BitsPerPixel << " bpp is not supported!!!\n";
  902. break;
  903. }
  904. assert(0);
  905. return NULL;
  906. }
  907. BlitterWithRotationVal CSDL_Ext::getBlitterWithRotationAndAlpha(SDL_Surface *dest)
  908. {
  909. switch(dest->format->BytesPerPixel)
  910. {
  911. case 2: return blitWithRotateClipValWithAlpha<2>;
  912. case 3: return blitWithRotateClipValWithAlpha<3>;
  913. case 4: return blitWithRotateClipValWithAlpha<4>;
  914. default:
  915. tlog1 << (int)dest->format->BitsPerPixel << " bpp is not supported!!!\n";
  916. break;
  917. }
  918. assert(0);
  919. return NULL;
  920. }
  921. template<int bpp>
  922. void CSDL_Ext::applyEffectBpp( SDL_Surface * surf, const SDL_Rect * rect, int mode )
  923. {
  924. switch(mode)
  925. {
  926. case 0: //sepia
  927. {
  928. const int sepiaDepth = 20;
  929. const int sepiaIntensity = 30;
  930. for(int xp = rect->x; xp < rect->x + rect->w; ++xp)
  931. {
  932. for(int yp = rect->y; yp < rect->y + rect->h; ++yp)
  933. {
  934. Uint8 * pixel = (ui8*)surf->pixels + yp * surf->pitch + xp * surf->format->BytesPerPixel;
  935. int r = Channels::px<bpp>::r.get(pixel);
  936. int g = Channels::px<bpp>::g.get(pixel);
  937. int b = Channels::px<bpp>::b.get(pixel);
  938. int gray = 0.299 * r + 0.587 * g + 0.114 *b;
  939. r = g = b = gray;
  940. r = r + (sepiaDepth * 2);
  941. g = g + sepiaDepth;
  942. if (r>255) r=255;
  943. if (g>255) g=255;
  944. if (b>255) b=255;
  945. // Darken blue color to increase sepia effect
  946. b -= sepiaIntensity;
  947. // normalize if out of bounds
  948. if (b<0) b=0;
  949. Channels::px<bpp>::r.set(pixel, r);
  950. Channels::px<bpp>::g.set(pixel, g);
  951. Channels::px<bpp>::b.set(pixel, b);
  952. }
  953. }
  954. }
  955. break;
  956. case 1: //grayscale
  957. {
  958. for(int xp = rect->x; xp < rect->x + rect->w; ++xp)
  959. {
  960. for(int yp = rect->y; yp < rect->y + rect->h; ++yp)
  961. {
  962. Uint8 * pixel = (ui8*)surf->pixels + yp * surf->pitch + xp * surf->format->BytesPerPixel;
  963. int r = Channels::px<bpp>::r.get(pixel);
  964. int g = Channels::px<bpp>::g.get(pixel);
  965. int b = Channels::px<bpp>::b.get(pixel);
  966. int gray = 0.299 * r + 0.587 * g + 0.114 *b;
  967. vstd::amax(gray, 255);
  968. Channels::px<bpp>::r.set(pixel, gray);
  969. Channels::px<bpp>::g.set(pixel, gray);
  970. Channels::px<bpp>::b.set(pixel, gray);
  971. }
  972. }
  973. }
  974. break;
  975. default:
  976. throw std::runtime_error("Unsupported effect!");
  977. }
  978. }
  979. void CSDL_Ext::applyEffect( SDL_Surface * surf, const SDL_Rect * rect, int mode )
  980. {
  981. switch(surf->format->BytesPerPixel)
  982. {
  983. case 2: applyEffectBpp<2>(surf, rect, mode); break;
  984. case 3: applyEffectBpp<3>(surf, rect, mode); break;
  985. case 4: applyEffectBpp<4>(surf, rect, mode); break;
  986. }
  987. }
  988. template<int bpp>
  989. void scaleSurfaceFastInternal(SDL_Surface *surf, SDL_Surface *ret)
  990. {
  991. const float factorX = float(surf->w) / float(ret->w),
  992. factorY = float(surf->h) / float(ret->h);
  993. for(int y = 0; y < ret->h; y++)
  994. {
  995. for(int x = 0; x < ret->w; x++)
  996. {
  997. //coordinates we want to calculate
  998. int origX = floor(factorX * x),
  999. origY = floor(factorY * y);
  1000. // Get pointers to source pixels
  1001. Uint8 *srcPtr = (Uint8*)surf->pixels + origY * surf->pitch + origX * bpp;
  1002. Uint8 *destPtr = (Uint8*)ret->pixels + y * ret->pitch + x * bpp;
  1003. memcpy(destPtr, srcPtr, bpp);
  1004. }
  1005. }
  1006. }
  1007. SDL_Surface * CSDL_Ext::scaleSurfaceFast(SDL_Surface *surf, int width, int height)
  1008. {
  1009. if (!surf || !width || !height)
  1010. return nullptr;
  1011. //Same size? return copy - this should more be faster
  1012. if (width == surf->w && height == surf->h)
  1013. return copySurface(surf);
  1014. SDL_Surface *ret = newSurface(width, height, surf);
  1015. switch(surf->format->BytesPerPixel)
  1016. {
  1017. case 1: scaleSurfaceFastInternal<1>(surf, ret); break;
  1018. case 2: scaleSurfaceFastInternal<2>(surf, ret); break;
  1019. case 3: scaleSurfaceFastInternal<3>(surf, ret); break;
  1020. case 4: scaleSurfaceFastInternal<4>(surf, ret); break;
  1021. }
  1022. return ret;
  1023. }
  1024. template<int bpp>
  1025. void scaleSurfaceInternal(SDL_Surface *surf, SDL_Surface *ret)
  1026. {
  1027. const float factorX = float(surf->w - 1) / float(ret->w),
  1028. factorY = float(surf->h - 1) / float(ret->h);
  1029. for(int y = 0; y < ret->h; y++)
  1030. {
  1031. for(int x = 0; x < ret->w; x++)
  1032. {
  1033. //coordinates we want to interpolate
  1034. float origX = factorX * x,
  1035. origY = factorY * y;
  1036. float x1 = floor(origX), x2 = floor(origX+1),
  1037. y1 = floor(origY), y2 = floor(origY+1);
  1038. //assert( x1 >= 0 && y1 >= 0 && x2 < surf->w && y2 < surf->h);//All pixels are in range
  1039. // Calculate weights of each source pixel
  1040. float w11 = ((origX - x1) * (origY - y1));
  1041. float w12 = ((origX - x1) * (y2 - origY));
  1042. float w21 = ((x2 - origX) * (origY - y1));
  1043. float w22 = ((x2 - origX) * (y2 - origY));
  1044. //assert( w11 + w12 + w21 + w22 > 0.99 && w11 + w12 + w21 + w22 < 1.01);//total weight is ~1.0
  1045. // Get pointers to source pixels
  1046. Uint8 *p11 = (Uint8*)surf->pixels + int(y1) * surf->pitch + int(x1) * bpp;
  1047. Uint8 *p12 = p11 + bpp;
  1048. Uint8 *p21 = p11 + surf->pitch;
  1049. Uint8 *p22 = p21 + bpp;
  1050. // Calculate resulting channels
  1051. #define PX(X, PTR) Channels::px<bpp>::X.get(PTR)
  1052. int resR = PX(r, p11) * w11 + PX(r, p12) * w12 + PX(r, p21) * w21 + PX(r, p22) * w22;
  1053. int resG = PX(g, p11) * w11 + PX(g, p12) * w12 + PX(g, p21) * w21 + PX(g, p22) * w22;
  1054. int resB = PX(b, p11) * w11 + PX(b, p12) * w12 + PX(b, p21) * w21 + PX(b, p22) * w22;
  1055. int resA = PX(a, p11) * w11 + PX(a, p12) * w12 + PX(a, p21) * w21 + PX(a, p22) * w22;
  1056. //assert(resR < 256 && resG < 256 && resB < 256 && resA < 256);
  1057. #undef PX
  1058. Uint8 *dest = (Uint8*)ret->pixels + y * ret->pitch + x * bpp;
  1059. Channels::px<bpp>::r.set(dest, resR);
  1060. Channels::px<bpp>::g.set(dest, resG);
  1061. Channels::px<bpp>::b.set(dest, resB);
  1062. Channels::px<bpp>::a.set(dest, resA);
  1063. }
  1064. }
  1065. }
  1066. // scaling via bilinear interpolation algorithm.
  1067. // NOTE: best results are for scaling in range 50%...200%.
  1068. // And upscaling looks awful right now - should be fixed somehow
  1069. SDL_Surface * CSDL_Ext::scaleSurface(SDL_Surface *surf, int width, int height)
  1070. {
  1071. if (!surf || !width || !height)
  1072. return nullptr;
  1073. if (surf->format->palette)
  1074. return scaleSurfaceFast(surf, width, height);
  1075. //Same size? return copy - this should more be faster
  1076. if (width == surf->w && height == surf->h)
  1077. return copySurface(surf);
  1078. SDL_Surface *ret = newSurface(width, height, surf);
  1079. switch(surf->format->BytesPerPixel)
  1080. {
  1081. case 2: scaleSurfaceInternal<2>(surf, ret); break;
  1082. case 3: scaleSurfaceInternal<3>(surf, ret); break;
  1083. case 4: scaleSurfaceInternal<4>(surf, ret); break;
  1084. }
  1085. return ret;
  1086. }
  1087. void CSDL_Ext::blitSurface( SDL_Surface * src, SDL_Rect * srcRect, SDL_Surface * dst, SDL_Rect * dstRect )
  1088. {
  1089. if (dst != screen)
  1090. {
  1091. SDL_BlitSurface(src, srcRect, dst, dstRect);
  1092. }
  1093. else
  1094. {
  1095. SDL_Rect betterDst;
  1096. if (dstRect)
  1097. {
  1098. betterDst = *dstRect;
  1099. }
  1100. else
  1101. {
  1102. betterDst = Rect(0, 0, dst->w, dst->h);
  1103. }
  1104. SDL_BlitSurface(src, srcRect, dst, &betterDst);
  1105. }
  1106. }
  1107. void CSDL_Ext::fillRect( SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color )
  1108. {
  1109. SDL_Rect newRect;
  1110. if (dstrect)
  1111. {
  1112. newRect = *dstrect;
  1113. }
  1114. else
  1115. {
  1116. newRect = Rect(0, 0, dst->w, dst->h);
  1117. }
  1118. SDL_FillRect(dst, &newRect, color);
  1119. }
  1120. void CSDL_Ext::fillTexture(SDL_Surface *dst, SDL_Surface * src)
  1121. {
  1122. SDL_Rect srcRect;
  1123. SDL_Rect dstRect;
  1124. SDL_GetClipRect(src, &srcRect);
  1125. SDL_GetClipRect(dst, &dstRect);
  1126. for (int y=dstRect.y; y < dstRect.y + dstRect.h; y+=srcRect.h)
  1127. {
  1128. for (int x=dstRect.x; x < dstRect.x + dstRect.w; x+=srcRect.w)
  1129. {
  1130. int xLeft = std::min<int>(srcRect.w, dstRect.x + dstRect.w - x);
  1131. int yLeft = std::min<int>(srcRect.h, dstRect.y + dstRect.h - y);
  1132. Rect currentDest(x, y, xLeft, yLeft);
  1133. SDL_BlitSurface(src, &srcRect, dst, &currentDest);
  1134. }
  1135. }
  1136. }
  1137. std::string CSDL_Ext::trimToFit(std::string text, int widthLimit, EFonts font)
  1138. {
  1139. int widthSoFar = 0;
  1140. for(auto i = text.begin(); i != text.end(); i++)
  1141. {
  1142. widthSoFar += graphics->fonts[font]->getCharWidth(*i);
  1143. if(widthSoFar > widthLimit)
  1144. {
  1145. //remove all characteres past limit
  1146. text.erase(i, text.end());
  1147. break;
  1148. }
  1149. }
  1150. return text;
  1151. }
  1152. template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<2>(int, int);
  1153. template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<3>(int, int);
  1154. template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<4>(int, int);