SDL_Extensions.cpp 36 KB

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