sge_rotation.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*
  2. * SDL Graphics Extension
  3. * Rotation routines
  4. *
  5. * Started 000625
  6. *
  7. * License: LGPL v2+ (see the file LICENSE)
  8. * (c)1999-2003 Anders Lindström
  9. */
  10. /* MODIFIED: 03/05/2004 Janson
  11. *
  12. * MODIFIED: Prefix ++/-- instead of postfix (consistent with my other code)
  13. * Removed all 8/24 bit code
  14. *
  15. * REMOVED: _sge_update and all related functions
  16. * Obsolete functions
  17. * Texture mapping version
  18. */
  19. /*********************************************************************
  20. * This library is free software; you can redistribute it and/or *
  21. * modify it under the terms of the GNU Library General Public *
  22. * License as published by the Free Software Foundation; either *
  23. * version 2 of the License, or (at your option) any later version. *
  24. *********************************************************************/
  25. // (MODIFIED Janson - using std header)
  26. #include "all.h"
  27. #define SWAP(x,y,temp) temp=x;x=y;y=temp
  28. extern Uint8 _sge_lock;
  29. //==================================================================================
  30. // Helper function to sge_transform()
  31. // Returns the bounding box
  32. //==================================================================================
  33. void _calcRect(SDL_Surface *src, SDL_Surface *dst, float theta, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax)
  34. {
  35. Sint16 x, y, rx, ry;
  36. // Clip to src surface
  37. Sint16 sxmin = sge_clip_xmin(src);
  38. Sint16 sxmax = sge_clip_xmax(src);
  39. Sint16 symin = sge_clip_ymin(src);
  40. Sint16 symax = sge_clip_ymax(src);
  41. Sint16 sx[]={sxmin, sxmax, sxmin, sxmax};
  42. Sint16 sy[]={symin, symax, symax, symin};
  43. // We don't really need fixed-point here
  44. // but why not?
  45. Sint32 const istx = Sint32((sin(theta)*xscale) * 8192.0); /* Inverse transform */
  46. Sint32 const ictx = Sint32((cos(theta)*xscale) * 8192.2);
  47. Sint32 const isty = Sint32((sin(theta)*yscale) * 8192.0);
  48. Sint32 const icty = Sint32((cos(theta)*yscale) * 8192.2);
  49. //Calculate the four corner points
  50. for(int i=0; i<4; ++i){
  51. rx = sx[i] - px;
  52. ry = sy[i] - py;
  53. x = Sint16(((ictx*rx - isty*ry) >> 13) + qx);
  54. y = Sint16(((icty*ry + istx*rx) >> 13) + qy);
  55. if(i==0){
  56. *xmax = *xmin = x;
  57. *ymax = *ymin = y;
  58. }else{
  59. if(x>*xmax)
  60. *xmax=x;
  61. else if(x<*xmin)
  62. *xmin=x;
  63. if(y>*ymax)
  64. *ymax=y;
  65. else if(y<*ymin)
  66. *ymin=y;
  67. }
  68. }
  69. //Better safe than sorry...
  70. *xmin -= 1;
  71. *ymin -= 1;
  72. *xmax += 1;
  73. *ymax += 1;
  74. //Clip to dst surface
  75. if( !dst )
  76. return;
  77. if( *xmin < sge_clip_xmin(dst) )
  78. *xmin = sge_clip_xmin(dst);
  79. if( *xmax > sge_clip_xmax(dst) )
  80. *xmax = sge_clip_xmax(dst);
  81. if( *ymin < sge_clip_ymin(dst) )
  82. *ymin = sge_clip_ymin(dst);
  83. if( *ymax > sge_clip_ymax(dst) )
  84. *ymax = sge_clip_ymax(dst);
  85. }
  86. /*==================================================================================
  87. ** Rotate by angle about pivot (px,py) scale by scale and place at
  88. ** position (qx,qy).
  89. **
  90. ** Transformation matrix application (rotated coords "R"):
  91. **
  92. ** / rx \ / cos(theta) sin(theta) \ / dx \
  93. ** | | = | | | |
  94. ** \ ry / \ -sin(theta) cos(theta) / \ dy /
  95. **
  96. ** => rx = cos(theta) dx + sin(theta) dy
  97. ** ry = cos(theta) dy - sin(theta) dx
  98. ** but represented as a fixed-point float using integer math
  99. **
  100. ** Developed with the help from Terry Hancock (hancock@earthlink.net)
  101. **
  102. **==================================================================================*/
  103. // First we need some macros to handle different bpp
  104. // I'm sorry about this...
  105. #define TRANSFORM(UintXX, DIV) \
  106. Sint32 const src_pitch=src->pitch/DIV; \
  107. Sint32 const dst_pitch=dst->pitch/DIV; \
  108. UintXX const *src_row = (UintXX *)src->pixels; \
  109. UintXX *dst_row; \
  110. \
  111. for (y=ymin; y<ymax; ++y){ \
  112. dy = y - qy; \
  113. \
  114. sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
  115. sy = Sint32(cty*dy - stdx + my); \
  116. \
  117. /* Calculate pointer to dst surface */ \
  118. dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
  119. \
  120. for (x=xmin; x<xmax; ++x){ \
  121. rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
  122. ry=Sint16(sy >> 13); \
  123. \
  124. /* Make sure the source pixel is actually in the source image. */ \
  125. if( (rx>=sxmin) && (rx<=sxmax) && (ry>=symin) && (ry<=symax) ) \
  126. *(dst_row + x) = *(src_row + ry*src_pitch + rx); \
  127. \
  128. sx += ctx; /* Incremental transformations */ \
  129. sy -= sty; \
  130. } \
  131. }
  132. #define TRANSFORM_GENERIC \
  133. Uint8 R, G, B, A; \
  134. \
  135. for (y=ymin; y<ymax; ++y){ \
  136. dy = y - qy; \
  137. \
  138. sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
  139. sy = Sint32(cty*dy - stdx + my); \
  140. \
  141. for (x=xmin; x<xmax; ++x){ \
  142. rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
  143. ry=Sint16(sy >> 13); \
  144. \
  145. /* Make sure the source pixel is actually in the source image. */ \
  146. if( (rx>=sxmin) && (rx<=sxmax) && (ry>=symin) && (ry<=symax) ){ \
  147. sge_GetRGBA(sge_GetPixel(src,rx,ry), src->format, &R, &G, &B, &A);\
  148. _PutPixelX(dst,x,y,sge_MapRGBA(dst->format, R, G, B, A)); \
  149. \
  150. } \
  151. sx += ctx; /* Incremental transformations */ \
  152. sy -= sty; \
  153. } \
  154. }
  155. // Interpolated transform
  156. #define TRANSFORM_AA(UintXX, DIV) \
  157. Sint32 const src_pitch=src->pitch/DIV; \
  158. Sint32 const dst_pitch=dst->pitch/DIV; \
  159. UintXX const *src_row = (UintXX *)src->pixels; \
  160. UintXX *dst_row; \
  161. UintXX c1, c2, c3, c4;\
  162. Uint32 R, G, B, A=0; \
  163. UintXX Rmask = src->format->Rmask, Gmask = src->format->Gmask, Bmask = src->format->Bmask, Amask = src->format->Amask;\
  164. Uint32 wx, wy;\
  165. Uint32 p1, p2, p3, p4;\
  166. \
  167. /*
  168. * Interpolation:
  169. * We calculate the distances from our point to the four nearest pixels, d1..d4.
  170. * d(a,b) = sqrt(a²+b²) ~= 0.707(a+b) (Pythagoras (Taylor) expanded around (0.5;0.5))
  171. *
  172. * 1 wx 2
  173. * *-|-* (+ = our point at (x,y))
  174. * | | | (* = the four nearest pixels)
  175. * wy --+ | wx = float(x) - int(x)
  176. * | | wy = float(y) - int(y)
  177. * *---*
  178. * 3 4
  179. * d1 = d(wx,wy) d2 = d(1-wx,wy) d3 = d(wx,1-wy) d4 = d(1-wx,1-wy)
  180. * We now want to weight each pixels importance - it's vicinity to our point:
  181. * w1=d4 w2=d3 w3=d2 w4=d1 (Yes it works... just think a bit about it)
  182. *
  183. * If the pixels have the colors c1..c4 then our point should have the color
  184. * c = (w1*c1 + w2*c2 + w3*c3 + w4*c4)/(w1+w2+w3+w4) (the weighted average)
  185. * but w1+w2+w3+w4 = 4*0.707 so we might as well write it as
  186. * c = p1*c1 + p2*c2 + p3*c3 + p4*c4 where p1..p4 = (w1..w4)/(4*0.707)
  187. *
  188. * But p1..p4 are fixed point so we can just divide the fixed point constant!
  189. * 8192/(4*0.71) = 2897 and we can skip 0.71 too (the division will cancel it everywhere)
  190. * 8192/4 = 2048
  191. *
  192. * 020102: I changed the fixed-point representation for the variables in the weighted average
  193. * to 24.7 to avoid problems with 32bit colors. Everything else is still 18.13. This
  194. * does however not solve the problem with 32bit RGBA colors...
  195. */\
  196. \
  197. Sint32 const one = 2048>>6; /* 1 in Fixed-point */ \
  198. Sint32 const two = 2*2048>>6; /* 2 in Fixed-point */ \
  199. \
  200. for (y=ymin; y<ymax; ++y){ \
  201. dy = y - qy; \
  202. \
  203. sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
  204. sy = Sint32(cty*dy - stdx + my); \
  205. \
  206. /* Calculate pointer to dst surface */ \
  207. dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
  208. \
  209. for (x=xmin; x<xmax; ++x){ \
  210. rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
  211. ry=Sint16(sy >> 13); \
  212. \
  213. /* Make sure the source pixel is actually in the source image. */ \
  214. if( (rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax) ){ \
  215. wx = (sx & 0x00001FFF) >>8; /* (float(x) - int(x)) / 4 */ \
  216. wy = (sy & 0x00001FFF) >>8;\
  217. \
  218. p4 = wx+wy;\
  219. p3 = one-wx+wy;\
  220. p2 = wx+one-wy;\
  221. p1 = two-wx-wy;\
  222. \
  223. c1 = *(src_row + ry*src_pitch + rx);\
  224. c2 = *(src_row + ry*src_pitch + rx+1);\
  225. c3 = *(src_row + (ry+1)*src_pitch + rx);\
  226. c4 = *(src_row + (ry+1)*src_pitch + rx+1);\
  227. \
  228. /* Calculate the average */\
  229. R = ((p1*(c1 & Rmask) + p2*(c2 & Rmask) + p3*(c3 & Rmask) + p4*(c4 & Rmask))>>7) & Rmask;\
  230. G = ((p1*(c1 & Gmask) + p2*(c2 & Gmask) + p3*(c3 & Gmask) + p4*(c4 & Gmask))>>7) & Gmask;\
  231. B = ((p1*(c1 & Bmask) + p2*(c2 & Bmask) + p3*(c3 & Bmask) + p4*(c4 & Bmask))>>7) & Bmask;\
  232. if(Amask)\
  233. A = ((p1*(c1 & Amask) + p2*(c2 & Amask) + p3*(c3 & Amask) + p4*(c4 & Amask))>>7) & Amask;\
  234. \
  235. *(dst_row + x) = R | G | B | A;\
  236. } \
  237. sx += ctx; /* Incremental transformations */ \
  238. sy -= sty; \
  239. } \
  240. }
  241. #define TRANSFORM_GENERIC_AA \
  242. Uint8 R, G, B, A, R1, G1, B1, A1=0, R2, G2, B2, A2=0, R3, G3, B3, A3=0, R4, G4, B4, A4=0; \
  243. Sint32 wx, wy, p1, p2, p3, p4;\
  244. \
  245. Sint32 const one = 2048; /* 1 in Fixed-point */ \
  246. Sint32 const two = 2*2048; /* 2 in Fixed-point */ \
  247. \
  248. for (y=ymin; y<ymax; ++y){ \
  249. dy = y - qy; \
  250. \
  251. sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
  252. sy = Sint32(cty*dy - stdx + my); \
  253. \
  254. for (x=xmin; x<xmax; ++x){ \
  255. rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
  256. ry=Sint16(sy >> 13); \
  257. \
  258. /* Make sure the source pixel is actually in the source image. */ \
  259. if( (rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax) ){ \
  260. wx = (sx & 0x00001FFF) >> 2; /* (float(x) - int(x)) / 4 */ \
  261. wy = (sy & 0x00001FFF) >> 2;\
  262. \
  263. p4 = wx+wy;\
  264. p3 = one-wx+wy;\
  265. p2 = wx+one-wy;\
  266. p1 = two-wx-wy;\
  267. \
  268. sge_GetRGBA(sge_GetPixel(src,rx, ry), src->format, &R1, &G1, &B1, &A1);\
  269. sge_GetRGBA(sge_GetPixel(src,rx+1,ry), src->format, &R2, &G2, &B2, &A2);\
  270. sge_GetRGBA(sge_GetPixel(src,rx, ry+1), src->format, &R3, &G3, &B3, &A3);\
  271. sge_GetRGBA(sge_GetPixel(src,rx+1,ry+1), src->format, &R4, &G4, &B4, &A4);\
  272. \
  273. /* Calculate the average */\
  274. R = (p1*R1 + p2*R2 + p3*R3 + p4*R4)>>13;\
  275. G = (p1*G1 + p2*G2 + p3*G3 + p4*G4)>>13;\
  276. B = (p1*B1 + p2*B2 + p3*B3 + p4*B4)>>13;\
  277. A = (p1*A1 + p2*A2 + p3*A3 + p4*A4)>>13;\
  278. \
  279. _PutPixelX(dst,x,y,sge_MapRGBA(dst->format, R, G, B, A)); \
  280. \
  281. } \
  282. sx += ctx; /* Incremental transformations */ \
  283. sy -= sty; \
  284. } \
  285. }
  286. // We get better performance if AA and normal rendering is seperated into two functions (better optimization).
  287. // sge_transform() is used as a wrapper.
  288. SDL_Rect sge_transformNorm(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
  289. {
  290. Sint32 dy, sx, sy;
  291. Sint16 x, y, rx, ry;
  292. SDL_Rect r;
  293. r.x = r.y = r.w = r.h = 0;
  294. float theta = float(angle*PI/180.0); /* Convert to radians. */
  295. // Here we use 18.13 fixed point integer math
  296. // Sint32 should have 31 usable bits and one for sign
  297. // 2^13 = 8192
  298. // Check scales
  299. Sint32 maxint = Sint32(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
  300. if( xscale == 0 || yscale == 0)
  301. return r;
  302. if( 8192.0/xscale > maxint )
  303. xscale = float(8192.0/maxint);
  304. else if( 8192.0/xscale < -maxint )
  305. xscale = float(-8192.0/maxint);
  306. if( 8192.0/yscale > maxint )
  307. yscale = float(8192.0/maxint);
  308. else if( 8192.0/yscale < -maxint )
  309. yscale = float(-8192.0/maxint);
  310. // Fixed-point equivalents
  311. Sint32 const stx = Sint32((sin(theta)/xscale) * 8192.0);
  312. Sint32 const ctx = Sint32((cos(theta)/xscale) * 8192.0);
  313. Sint32 const sty = Sint32((sin(theta)/yscale) * 8192.0);
  314. Sint32 const cty = Sint32((cos(theta)/yscale) * 8192.0);
  315. Sint32 const mx = Sint32(px*8192.0);
  316. Sint32 const my = Sint32(py*8192.0);
  317. // Compute a bounding rectangle
  318. Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
  319. _calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
  320. // Clip to src surface
  321. Sint16 sxmin = sge_clip_xmin(src);
  322. Sint16 sxmax = sge_clip_xmax(src);
  323. Sint16 symin = sge_clip_ymin(src);
  324. Sint16 symax = sge_clip_ymax(src);
  325. // Some terms in the transform are constant
  326. Sint32 const dx = xmin - qx;
  327. Sint32 const ctdx = ctx*dx;
  328. Sint32 const stdx = sty*dx;
  329. // Lock surfaces... hopfully less than two needs locking!
  330. if ( SDL_MUSTLOCK(src) && _sge_lock )
  331. if ( SDL_LockSurface(src) < 0 )
  332. return r;
  333. if ( SDL_MUSTLOCK(dst) && _sge_lock ){
  334. if ( SDL_LockSurface(dst) < 0 ){
  335. if ( SDL_MUSTLOCK(src) && _sge_lock )
  336. SDL_UnlockSurface(src);
  337. return r;
  338. }
  339. }
  340. // Use the correct bpp
  341. if( src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 && !(flags&SGE_TSAFE) ){
  342. switch( src->format->BytesPerPixel ){
  343. case 2: { /* Probably 15-bpp or 16-bpp */
  344. TRANSFORM(Uint16, 2)
  345. }
  346. break;
  347. case 4: { /* Probably 32-bpp */
  348. TRANSFORM(Uint32, 4)
  349. }
  350. break;
  351. }
  352. }else{
  353. TRANSFORM_GENERIC
  354. }
  355. // Unlock surfaces
  356. if ( SDL_MUSTLOCK(src) && _sge_lock )
  357. SDL_UnlockSurface(src);
  358. if ( SDL_MUSTLOCK(dst) && _sge_lock )
  359. SDL_UnlockSurface(dst);
  360. //Return the bounding rectangle
  361. r.x=xmin; r.y=ymin; r.w=xmax-xmin; r.h=ymax-ymin;
  362. return r;
  363. }
  364. SDL_Rect sge_transformAA(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
  365. {
  366. Sint32 dy, sx, sy;
  367. Sint16 x, y, rx, ry;
  368. SDL_Rect r;
  369. r.x = r.y = r.w = r.h = 0;
  370. float theta = float(angle*PI/180.0); /* Convert to radians. */
  371. // Here we use 18.13 fixed point integer math
  372. // Sint32 should have 31 usable bits and one for sign
  373. // 2^13 = 8192
  374. // Check scales
  375. Sint32 maxint = Sint32(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
  376. if( xscale == 0 || yscale == 0)
  377. return r;
  378. if( 8192.0/xscale > maxint )
  379. xscale = float(8192.0/maxint);
  380. else if( 8192.0/xscale < -maxint )
  381. xscale = float(-8192.0/maxint);
  382. if( 8192.0/yscale > maxint )
  383. yscale = float(8192.0/maxint);
  384. else if( 8192.0/yscale < -maxint )
  385. yscale = float(-8192.0/maxint);
  386. // Fixed-point equivalents
  387. Sint32 const stx = Sint32((sin(theta)/xscale) * 8192.0);
  388. Sint32 const ctx = Sint32((cos(theta)/xscale) * 8192.0);
  389. Sint32 const sty = Sint32((sin(theta)/yscale) * 8192.0);
  390. Sint32 const cty = Sint32((cos(theta)/yscale) * 8192.0);
  391. Sint32 const mx = Sint32(px*8192.0);
  392. Sint32 const my = Sint32(py*8192.0);
  393. // Compute a bounding rectangle
  394. Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
  395. _calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
  396. // Clip to src surface
  397. Sint16 sxmin = sge_clip_xmin(src);
  398. Sint16 sxmax = sge_clip_xmax(src);
  399. Sint16 symin = sge_clip_ymin(src);
  400. Sint16 symax = sge_clip_ymax(src);
  401. // Some terms in the transform are constant
  402. Sint32 const dx = xmin - qx;
  403. Sint32 const ctdx = ctx*dx;
  404. Sint32 const stdx = sty*dx;
  405. // Lock surfaces... hopfully less than two needs locking!
  406. if ( SDL_MUSTLOCK(src) && _sge_lock )
  407. if ( SDL_LockSurface(src) < 0 )
  408. return r;
  409. if ( SDL_MUSTLOCK(dst) && _sge_lock ){
  410. if ( SDL_LockSurface(dst) < 0 ){
  411. if ( SDL_MUSTLOCK(src) && _sge_lock )
  412. SDL_UnlockSurface(src);
  413. return r;
  414. }
  415. }
  416. // Use the correct bpp
  417. if( src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 && !(flags&SGE_TSAFE) ){
  418. switch( src->format->BytesPerPixel ){
  419. case 2: { /* Probably 15-bpp or 16-bpp */
  420. //TRANSFORM_AA(Uint16, 2)
  421. TRANSFORM_GENERIC_AA
  422. }
  423. break;
  424. case 4: { /* Probably 32-bpp */
  425. //TRANSFORM_AA(Uint32, 4)
  426. TRANSFORM_GENERIC_AA
  427. }
  428. break;
  429. }
  430. }else{
  431. TRANSFORM_GENERIC_AA
  432. }
  433. // Unlock surfaces
  434. if ( SDL_MUSTLOCK(src) && _sge_lock )
  435. SDL_UnlockSurface(src);
  436. if ( SDL_MUSTLOCK(dst) && _sge_lock )
  437. SDL_UnlockSurface(dst);
  438. //Return the bounding rectangle
  439. r.x=xmin; r.y=ymin; r.w=xmax-xmin; r.h=ymax-ymin;
  440. return r;
  441. }
  442. SDL_Rect sge_transform(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
  443. {
  444. if(flags&SGE_TAA)
  445. return sge_transformAA(src, dst, angle, xscale, yscale, px, py, qx, qy, flags);
  446. else
  447. return sge_transformNorm(src, dst, angle, xscale, yscale, px, py, qx, qy, flags);
  448. }
  449. //==================================================================================
  450. // Same as sge_transform() but returns an surface with the result
  451. //==================================================================================
  452. SDL_Surface *sge_transform_surface(SDL_Surface *src, Uint32 bcol, float angle, float xscale, float yscale, Uint8 flags)
  453. {
  454. float theta = float(angle*PI/180.0); /* Convert to radians. */
  455. // Compute a bounding rectangle
  456. Sint16 xmin=0, xmax=0, ymin=0, ymax=0;
  457. _calcRect(src, NULL, theta, xscale, yscale, 0, 0, 0, 0, &xmin,&ymin, &xmax,&ymax);
  458. Sint16 w = xmax-xmin+1;
  459. Sint16 h = ymax-ymin+1;
  460. Sint16 qx = -xmin;
  461. Sint16 qy = -ymin;
  462. SDL_Surface *dest;
  463. dest = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
  464. if(!dest)
  465. return NULL;
  466. sge_ClearSurface(dest,bcol); //Set background color
  467. sge_transform(src, dest, angle, xscale, yscale, 0, 0, qx, qy, flags);
  468. return dest;
  469. }