rotate.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. I AM ARCHAIC ! REMOVE ME AT ONCE AND ADD ROTATE96.CPP!
  19. // This should include RotShrink, RotOrtho, and R90
  20. //
  21. #ifdef PATHS_IN_INCLUDES
  22. #include "GREEN/BLiT/BLIT.H"
  23. #else
  24. #include "BLIT.H"
  25. #endif
  26. #ifdef PATHS_IN_INCLUDES
  27. #include "GREEN/BLiT/_BlitInt.H"
  28. #else
  29. #include "_BlitInt.H"
  30. #endif
  31. #include <math.h>
  32. // Turn off warnings for assignments within expressions
  33. #ifdef __MWERKS__
  34. #pragma warn_possunwant off
  35. #endif
  36. class RSaveOld
  37. {
  38. public:
  39. ULONG m_type;
  40. short sX;
  41. short sY;
  42. short sW;
  43. short sH;
  44. };
  45. // I hate doing this, but let's make a type for a square rotation buffer.
  46. // It can be used by both algorithms (QuickRot and OrthoRot)
  47. // Use of live rotation saves enough memory to kind-of justify the buffer
  48. // space lost....
  49. //
  50. // Will convert from any 8bpp format.
  51. //
  52. short ConvertToROTBUF(RImage* pImage);
  53. // Will convert back to type BMP8
  54. //
  55. short ConvertFromROTBUF(RImage* pImage);
  56. // Will delete pSpecial
  57. //
  58. short DeleteROTBUF(RImage* pImage);
  59. const short csFlag = -32767;
  60. short gsCX = csFlag,gsCY = csFlag; // Will be reset each time to csFlag! (A default code)
  61. void rspSetConvertToROTBUF(short sCenterX,short sCenterY)
  62. {
  63. gsCX = sCenterX;
  64. gsCY = sCenterY;
  65. }
  66. // shoudln't need a special delete!
  67. IMAGELINKLATE(ROTBUF,ConvertToROTBUF,ConvertFromROTBUF, NULL,NULL,NULL,DeleteROTBUF);
  68. // Use for cool things!
  69. static const double sqrt2 = (double)1.414213562373;
  70. // Must be an UNCOMPRESSED Image type!
  71. // It does NOT currently Lasso the image! You must do it fist if you care!
  72. // It DOES use (cx,cy) as sey by rspSetConvertToROTBUF
  73. //
  74. short ConvertToROTBUF(RImage* pImage)
  75. {
  76. if (!ImageIsUncompressed(pImage->m_type))
  77. {
  78. TRACE("Convert: Can only make a ROTBUF type from an UNCOMPRESSED typer!\n");
  79. return RImage::NOT_SUPPORTED;
  80. }
  81. // The key to the ROTBUF is to provide an amount of padding around the buffer
  82. // sufficient to deal with rotation:
  83. // in standard way, I wil create a dummy image to BLiT to, then swap buffers and
  84. // destroy it!
  85. // The theme for this type of extended buffer is as follows:
  86. //
  87. // long lBufferWidth; // Width of ROTATING buffer = 2 * sC!!!!!
  88. // sC = sqrt2 * R, sP = sL = sqrt2 * sR
  89. // long lBufferHeight;// Same number as above
  90. // long lXPos; // Position of image in the buffer
  91. // long lYPos; // Position of image in the buffer
  92. // void* pSpecial; // This holds the previous data type!
  93. RImage imTemp; // this will hold the new image!
  94. // Get the coordinates of the center of rotation!
  95. if (gsCX == csFlag) gsCX = (pImage->m_sWidth >> 1);
  96. if (gsCY == csFlag) gsCY = (pImage->m_sHeight >> 1);
  97. // reset the input parameters to default:
  98. long cx = (long)gsCX;
  99. long cy = (long)gsCY;
  100. //****************** APPROXIMATE THE RADIUS *********************
  101. // Use the Sprite's dimensions as a simple way to calculate
  102. // it's radius about the cor...
  103. // NOTE: sqruared values of shorts must be longs!
  104. long d1 = (SQR(cx)+SQR(cy)); // Distance from (0,0)
  105. long d2 = (SQR(cx)+SQR(pImage->m_sHeight - cy - 1));
  106. long d3 = (SQR(pImage->m_sWidth - cx - 1)+SQR(cy));
  107. long d4 = (SQR(pImage->m_sWidth - cx - 1)+SQR(pImage->m_sHeight - cy - 1));
  108. long lR = MAX(MAX(d1,d2),MAX(d3,d4)); // distance squared
  109. lR = (long)(sqrt(double(lR)) + 0.9999); // actual longest distance, rounded up
  110. long lC = (long)(sqrt2 * lR + 1);// round up
  111. long lNewW = (long)(lC<<1); // new buffer width a test:
  112. // Store the rotating window size in this field:
  113. pImage->m_sWinWidth = pImage->m_sWinHeight = (lR<<1);
  114. // Find a new pitch
  115. long lNewP = (lNewW + 15) & ~15;
  116. // Create a new buffer:
  117. imTemp.CreateImage((short)lNewW,(short)lNewW,pImage->m_type,lNewP,
  118. pImage->m_sDepth);
  119. // Find the offset:
  120. pImage->m_sWinX = lC - cx;
  121. pImage->m_sWinY = lC - cy;
  122. // BLiT the old image buffer into the new!
  123. rspBlit(pImage,&imTemp,(short)0,(short)0,
  124. pImage->m_sWinX,pImage->m_sWinY,
  125. pImage->m_sWidth,pImage->m_sHeight);
  126. // Now transfer it ALL back to the original buffer!
  127. UCHAR *pBuf = NULL,*pMem = NULL;
  128. imTemp.DetachData((void**)&pMem,(void**)&pBuf);
  129. // Kill Old:
  130. pImage->DestroyData();
  131. // Attach New
  132. pImage->m_pMem = pMem;
  133. pImage->m_pData = pBuf;
  134. // Validate the new Image, and save the old parameters:
  135. RSaveOld* pSave = new RSaveOld;
  136. pSave->m_type = pImage->m_type;
  137. pSave->sW = pImage->m_sWidth;
  138. pSave->sH = pImage->m_sHeight;
  139. pSave->sX = pImage->m_sWinX;
  140. pSave->sY = pImage->m_sWinY;
  141. pImage->m_pSpecialMem = pImage->m_pSpecial = (UCHAR*) pSave;
  142. pImage->m_type = RImage::ROTBUF;
  143. pImage->m_sWidth = imTemp.m_sWidth;
  144. pImage->m_sHeight = imTemp.m_sHeight;
  145. pImage->m_lPitch = imTemp.m_lPitch;
  146. pImage->m_ulSize = imTemp.m_ulSize;
  147. // Destroy Entire temporary Image
  148. // imTemp is on the stack and will auto-delete
  149. gsCY = gsCX = csFlag;
  150. return RImage::ROTBUF;
  151. }
  152. // Will convert back to the original type
  153. //
  154. short ConvertFromROTBUF(RImage* pImage)
  155. {
  156. RSaveOld* pSave = (RSaveOld*)(pImage->m_pSpecial);
  157. // Get rid of the extra padding:
  158. rspCrop(pImage,pSave->sX,pSave->sY,pSave->sW,pSave->sH);
  159. // Restore the member state:
  160. pImage->m_type = (RImage::Type)pSave->m_type;
  161. delete pSave;
  162. pImage->m_pSpecialMem = pImage->m_pSpecial = NULL;
  163. pImage->m_sWinWidth = pImage->m_sWinHeight = 0;
  164. pImage->m_sWinX = pImage->m_sWinY = 0;
  165. return pImage->m_type;
  166. }
  167. // Will delete pSpecial
  168. //
  169. short DeleteROTBUF(RImage* pImage)
  170. {
  171. delete pImage->m_pSpecial;
  172. return 0;
  173. }
  174. //************* This will be incorporated into REAL commands later:
  175. typedef struct tagPt {short x; short y;} Pt;
  176. // a 2D line based on 2D coordinates
  177. typedef struct tagLine1
  178. {
  179. long lNumX; // Fractional accumulator
  180. long lNumY;
  181. long lIncX; // Fractional Increment
  182. long lIncY;
  183. long lDelX; // Default Integral Increment for slopes > 1 as
  184. long lDelY; // dictated by the Dst W & H....
  185. long lDen;
  186. long lCurX; // Current point position
  187. long lCurY;
  188. long lPitchX; // Conditional adding to current position
  189. long lPitchY;
  190. } Line1;
  191. // A 2D line based on a single memory pointer...
  192. typedef struct tagLine2
  193. {
  194. long lNumX; // Fractional accumulator
  195. long lNumY;
  196. long lIncX; // Fractional Increment
  197. long lIncY;
  198. long lDel; // Default Integral Increment for slopes > 1 as
  199. long lDen;
  200. UCHAR* pCur; // Current point position
  201. long lPitchX; // Conditional adding to current position
  202. long lPitchY;
  203. } Line2;
  204. // Initialize the integral calculus
  205. // Overload the init function for each type of line:
  206. // d = the number of steps from pt 1 to pt 2...
  207. inline void initLine(Line1* pLine,
  208. long x1,long y1,long x2,long y2,long d)
  209. {
  210. long lDelX = x2 - x1,lDelY = y2 - y1;
  211. pLine->lCurX = x1;
  212. pLine->lCurY = y1;
  213. pLine->lDen = d;
  214. pLine->lNumX = pLine->lNumY = d>>1;
  215. pLine->lPitchX = SGN(lDelX);
  216. pLine->lPitchY = SGN(lDelY); // could add pitch
  217. pLine->lDelX = lDelX / d; // floor value of default pitch...
  218. pLine->lDelY = lDelY / d; // could add pitch
  219. lDelX = ABS(lDelX);
  220. lDelY = ABS(lDelY);
  221. pLine->lIncX = lDelX % d;
  222. pLine->lIncY = lDelY % d;
  223. }
  224. // d = the number of steps from pt 1 to pt 2...
  225. inline void initLine(Line2* pLine,UCHAR* pBase,long lPitch,
  226. long x1,long y1,long x2,long y2,long d)
  227. {
  228. long lDelX = x2 - x1,lDelY = y2 - y1;
  229. pLine->pCur = pBase + x1 + y1 * lPitch;
  230. pLine->lDen = d;
  231. pLine->lNumX = pLine->lNumY = (long)d>>1;
  232. pLine->lPitchX = SGN(lDelX);
  233. pLine->lPitchY = SGN(lDelY)*lPitch;
  234. pLine->lDel = (lDelX / d) + (lDelY / d)*lPitch;
  235. lDelX = ABS(lDelX);
  236. lDelY = ABS(lDelY);
  237. pLine->lIncX = lDelX % d;
  238. pLine->lIncY = lDelY % d;
  239. }
  240. // Increments along the line
  241. // Overload the init function for each type of line:
  242. inline void incLine(Line1& Line)
  243. {
  244. Line.lCurX += Line.lDelX;
  245. Line.lCurY += Line.lDelY;
  246. Line.lNumX += Line.lIncX;
  247. Line.lNumY += Line.lIncY;
  248. if (Line.lNumX > Line.lDen) {Line.lNumX-=Line.lDen;Line.lCurX+=Line.lPitchX;}
  249. if (Line.lNumY > Line.lDen) {Line.lNumY-=Line.lDen;Line.lCurY+=Line.lPitchY;}
  250. }
  251. inline void incLine(Line2& Line)
  252. {
  253. Line.pCur += Line.lDel;
  254. Line.lNumX += Line.lIncX;
  255. Line.lNumY += Line.lIncY;
  256. if (Line.lNumX > Line.lDen) {Line.lNumX-=Line.lDen;Line.pCur+=Line.lPitchX;}
  257. if (Line.lNumY > Line.lDen) {Line.lNumY-=Line.lDen;Line.pCur+=Line.lPitchY;}
  258. }
  259. // FLIPPING FLAGS:
  260. #define PRE_FLIP_H 1
  261. #define PRE_FLIP_V 2
  262. #define POST_FLIP_H 4
  263. #define POST_FLIP_V 8
  264. #define PtSwap(a,b) temp=a;a=b;b=temp
  265. //
  266. // It currently just clips to the destination buffer:
  267. //
  268. void _RotateShrink(float fDeg,RImage* pimSrc,RImage* pimDst,
  269. short sDstX,short sDstY,short sDstW,short sDstH, // = 2R = lBufferWidth
  270. short sFlipCode)
  271. {
  272. #ifdef _DEBUG
  273. if (pimSrc->m_type != RImage::ROTBUF)
  274. {
  275. TRACE("_RotateShrink: Source must be type ROTBUF!\n");
  276. return;
  277. }
  278. if (!ImageIsUncompressed(pimDst->m_type))
  279. {
  280. TRACE("_RotateShrink: Dest must be uncompressed!\n");
  281. return;
  282. }
  283. #endif
  284. //****************** Destination Clipper ***********************
  285. short sClip=0,sClipL=0,sClipR=0,sClipT=0,sClipB=0;
  286. short gsClipX,gsClipY,gsClipW,gsClipH;
  287. // Init clip rect:
  288. gsClipX = 0; // Cheezy for now...
  289. gsClipY = 0;
  290. gsClipW = pimDst->m_sWidth;
  291. gsClipH = pimDst->m_sHeight;
  292. // Optimize for noclip case:
  293. if ((sClip = gsClipX - sDstX)>0) sClipL = sClip;
  294. if ((sClip = gsClipY - sDstY)>0) sClipT = sClip;
  295. if ((sClip = sDstX + sDstW - gsClipX - gsClipW)>0) sClipR = sClip;
  296. if ((sClip = sDstY + sDstH - gsClipY - gsClipH)>0) sClipB = sClip;
  297. if (!sClipL && !sClipR && !sClipT && !sClipB) // not clipped
  298. {
  299. // ONLY implement unclipped BLiT for now!
  300. static double PI = 4.0 * atan(1.0);
  301. double dRad = (double)fDeg * PI/(double)180.0;
  302. double dCos = cos(dRad);
  303. double dSin = sin(dRad);
  304. double x,y;
  305. short i,j;
  306. Pt pCorners[4];
  307. Line1 l1Left,l1Right;
  308. Line2 l2Across; // need 3 lines...
  309. long lP = pimDst->m_lPitch;
  310. UCHAR *pDst,*pDstLine;
  311. Pt temp;
  312. UCHAR pixel; // ERROR 8-bit color!
  313. pDst = pimDst->m_pData + (long)sDstX + ((long)(sDstY))*lP;
  314. pDstLine = pDst;
  315. short sR = (short)((pimSrc->m_sWinWidth>>1)); // rotating box half side...
  316. short sC = (short)(sqrt2 * sR); // buffer half side...
  317. x = y = (double)-sR;
  318. //sDstW /= sqrt2;// crude patch
  319. //sDstH /= sqrt2;
  320. // Rotate Master Corner...
  321. pCorners[0].x = x * dCos + y * dSin;
  322. pCorners[0].y = y * dCos - x * dSin;
  323. // R90 to other corners, add flipping:
  324. pCorners[1].x = +pCorners[0].y;
  325. pCorners[1].y = -pCorners[0].x;
  326. pCorners[2].x = -pCorners[0].y;
  327. pCorners[2].y = +pCorners[0].x;
  328. pCorners[3].x = -pCorners[0].x;
  329. pCorners[3].y = -pCorners[0].y;
  330. // Do the simple flips about the origin:
  331. if (sFlipCode)
  332. {
  333. if (sFlipCode & PRE_FLIP_H) // HFLIP
  334. for (i=0;i<4;i++) pCorners[i].x = -pCorners[i].x;
  335. if (sFlipCode & PRE_FLIP_V) // VFLIP
  336. for (i=0;i<4;i++) pCorners[i].y = -pCorners[i].y;
  337. if (sFlipCode & POST_FLIP_H) // Dst Flip Horiz:
  338. {
  339. PtSwap(pCorners[0],pCorners[2]);
  340. PtSwap(pCorners[1],pCorners[3]);
  341. }
  342. if (sFlipCode & POST_FLIP_V) // Dst Flip Horiz:
  343. {
  344. PtSwap(pCorners[0],pCorners[1]);
  345. PtSwap(pCorners[2],pCorners[3]);
  346. }
  347. }
  348. for (i=0;i<4;i++)
  349. {
  350. pCorners[i].x += sC; // sC should BE buffersize/2
  351. pCorners[i].y += sC;
  352. }
  353. /*
  354. for (i=0;i<4;i++)
  355. {
  356. pCorners[i].x += pimSrc->lWidth / 2;
  357. pCorners[i].y += pimSrc->lHeight /2;
  358. }
  359. */
  360. // Set up the struts of the ladder:
  361. initLine(&l1Left,pCorners[0].x,pCorners[0].y,
  362. pCorners[1].x,pCorners[1].y,sDstH); // length of side = 2R
  363. initLine(&l1Right,pCorners[2].x,pCorners[2].y,
  364. pCorners[3].x,pCorners[3].y,sDstH);
  365. initLine(&l2Across,pimSrc->m_pData,pimSrc->m_lPitch,pCorners[0].x,pCorners[0].y,
  366. pCorners[2].x,pCorners[2].y,sDstW);
  367. // DRAW THE SUCKER!!!! (YAYA!)
  368. for (j=0;j<sDstH;j++,pDst = (pDstLine += lP) ) // line by line:
  369. {
  370. for (i=0,pDst = pDstLine;i<sDstW;i++)
  371. {
  372. // leap across:
  373. if (pixel = *l2Across.pCur) // 0x006fa06c
  374. *pDst = pixel;
  375. pDst++;
  376. incLine(l2Across);
  377. }
  378. // Advance the rungs!
  379. incLine(l1Left);
  380. incLine(l1Right);
  381. // Initialize a new rung across...
  382. initLine(&l2Across,pimSrc->m_pData,(short)pimSrc->m_lPitch,
  383. l1Left.lCurX,l1Left.lCurY,
  384. l1Right.lCurX,l1Right.lCurY,sDstW);
  385. }
  386. return;
  387. }
  388. // Check for no draw case:
  389. if ( sClipL >= sDstW ) return;
  390. if ( sClipR >= sDstW ) return;
  391. if ( sClipT >= sDstH ) return;
  392. if ( sClipB >= sDstH ) return;
  393. //******************************************************************
  394. // Partially clipped:
  395. TRACE("Rotate BLit: Clipping BLiT NYI!\n");
  396. //BLT_ProtoRotAndClip(pfrSrc,sDeg,pbkdDst,sDstX,sDstY,sDstW,sDstH,
  397. // sClipL,sClipR,sClipT,sClipB,sFlipCode,sAF);
  398. }
  399. //*****************************************************************************
  400. //*****************************************************************************
  401. //*****************************************************************************
  402. // For now, let's do a crude stub for BLT_Strafe:
  403. // It is only intended to allow CMA to compile for now,
  404. // and it's functionality WILL change!
  405. //
  406. // The goal is to create a series of pointers and links
  407. // which are merely copies of the original frame
  408. // The future strafe will NOT use a special structure type,
  409. // and the old strafe will probably be dropped!
  410. //
  411. /*
  412. CStrafe* BLT_RotStrafe(CImage* pimSrc,short sHotX,short sHotY,short sNumInc,
  413. short sDstH,short sNumLinks,short *psX, short* psY)
  414. {
  415. /*
  416. #ifdef _DEBUG
  417. if (!pimSrc) {TRACE("BLT_STRAFE: null src image!\n"); return NULL;}
  418. if (sNumInc < 1) {TRACE("BLT_STRAFE: no frames specified!\n"); return NULL;}
  419. if (sNumLinks && (!psX || !psY))
  420. {TRACE("BLT_STRAFE: null links passed!\n"); return NULL;}
  421. if (sDstH > (short)pimSrc->lHeight)
  422. {TRACE("BLT_STRAFE: magnification not currently supported!\n"); return NULL;}
  423. #endif
  424. Strafe* pStrafe = (Strafe*) calloc(1,sizeof(Strafe));
  425. pStrafe->sNumFrames = sNumInc;
  426. pStrafe->sNumLinks = sNumLinks;
  427. pStrafe->pFrame = (StrafeFrame*) calloc(sNumInc,sizeof(StrafeFrame) );
  428. short i,j;
  429. for (i=0;i<sNumLinks;i++)
  430. {
  431. psX[i] -= sHotX; // get position relative to hot spot:
  432. psY[i] -= sHotY;
  433. }
  434. for (i=0;i<sNumInc;i++)
  435. {
  436. pStrafe->pFrame[i].pfspr = pimSrc; // pt to original
  437. pStrafe->pFrame[i].sHotX = 0;
  438. pStrafe->pFrame[i].sHotY = 0;
  439. pStrafe->pFrame[i].sCurDeg = 0;
  440. if (sNumLinks == 0) pStrafe->pFrame[i].psLinkX = pStrafe->pFrame[i].psLinkY = NULL;
  441. else // create space for links:
  442. {
  443. pStrafe->pFrame[i].psLinkX = (short*)calloc(sNumLinks,sizeof(short));
  444. pStrafe->pFrame[i].psLinkY = (short*)calloc(sNumLinks,sizeof(short));
  445. // Set all the links:
  446. for (j=0;j<sNumLinks;j++)
  447. {
  448. pStrafe->pFrame[i].psLinkX[j] = psX[j]; // same links!
  449. pStrafe->pFrame[i].psLinkY[j] = psX[j];
  450. }
  451. }
  452. }
  453. return pStrafe;
  454. }
  455. */
  456. /*
  457. void BLT_FreeStrafe(Strafe* pStrafe)
  458. {
  459. if (pStrafe == NULL) return;
  460. short i;
  461. for (i=0;i<pStrafe->sNumFrames;i++)
  462. {
  463. if (pStrafe->pFrame != NULL)
  464. {
  465. if (pStrafe->pFrame[i].psLinkX != NULL)
  466. free(pStrafe->pFrame[i].psLinkX);
  467. if (pStrafe->pFrame[i].psLinkY != NULL)
  468. free(pStrafe->pFrame[i].psLinkY);
  469. }
  470. }
  471. }
  472. */
  473. // In this version, You must supply the host structure, which you may define, but which
  474. // must contain the following:
  475. //
  476. short rspStrafeRotate(void *pReturnArray, // Output
  477. RImage* pimSrc,short sCenterX,short sCenterY,double dScale, // Input
  478. short sNumFrames,double dStartDeg,double dDegInc,
  479. short sNumLinks,short *psX,short *psY, // input
  480. // generic user stucture must be an array:
  481. RImage* pIm, short *psHotX, short *psHotY,
  482. short **ppsX,short **ppsY,
  483. long lStructSize)
  484. {
  485. #ifdef _DEBUG
  486. if (!pimSrc)
  487. {
  488. TRACE("rspStrafeRotate: NULL source passed!\n");
  489. return -1;
  490. }
  491. if (!pReturnArray)
  492. {
  493. TRACE("rspStrafeRotate: NULL receiver passed!\n");
  494. return -1;
  495. }
  496. if (sNumFrames < 1)
  497. {
  498. TRACE("rspStrafeRotate: Bad number of frames!\n");
  499. return -1;
  500. }
  501. if (!ImageIsUncompressed(pimSrc->m_type))
  502. {
  503. TRACE("rspStrafeRotate:Need an uncompressed image format!\n");
  504. return -1;
  505. }
  506. if ((dScale <= 0.0) || (dScale > 1.0))
  507. {
  508. TRACE("rspStrafeRotate: Scale error: can only reduce for now!\n");
  509. return -1;
  510. }
  511. #endif
  512. //* FOR TESTING ONLY:
  513. RImage* pimBuf,*pimScreen;
  514. rspNameBuffers(&pimBuf,&pimScreen);
  515. union { short *pL; UCHAR *pB; } pHotX,pHotY;
  516. union { short **ppL; UCHAR *pB; } ppLinkX,ppLinkY;
  517. union { RImage **ppI; UCHAR *pB; } ppBuf;
  518. // default to a CStrafe:
  519. //
  520. if (!pIm) ppBuf.ppI = &(((CStrafe*)pReturnArray)->pImage);
  521. if (!psHotX) pHotX.pL = &((CStrafe*)pReturnArray)->sHotX;
  522. if (!psHotY) pHotY.pL = &((CStrafe*)pReturnArray)->sHotY;
  523. if (!ppsX) ppLinkX.ppL = &((CStrafe*)pReturnArray)->psLinkX;
  524. if (!ppsY) ppLinkY.ppL = &((CStrafe*)pReturnArray)->psLinkY;
  525. double dCurDeg = dStartDeg;
  526. // calculate degree increment in default case:
  527. if (dDegInc == 0.0) dDegInc = 360.0 / (double)sNumFrames;
  528. // Phase one: make the source ROTBUF, and create a destination
  529. rspSetConvertToROTBUF(sCenterX,sCenterY);
  530. ULONG ulOldType = pimSrc->m_type;
  531. if (pimSrc->Convert(RImage::ROTBUF)!= RImage::ROTBUF)
  532. {
  533. TRACE("rspStrafeRotate: Internal Conversion error\n");
  534. return -1;
  535. }
  536. //Calculate the appropriate height:
  537. short sDstH = (short)(dScale * pimSrc->m_sWinHeight);
  538. // Make a copy of the input links so they can be center adjusted
  539. short *psLinkX = NULL, *psLinkY = NULL;
  540. short j;
  541. if (sNumLinks > 0)
  542. {
  543. psLinkX = (short*)calloc(sizeof(short),sNumLinks);
  544. psLinkY = (short*)calloc(sizeof(short),sNumLinks);
  545. for (j=0;j<sNumLinks;j++)
  546. {
  547. psLinkX[j] = psX[j] - sCenterX;
  548. psLinkY[j] = psY[j] - sCenterY;
  549. }
  550. }
  551. // DO the strafing:
  552. short i;
  553. double scale = (double)sDstH / (double) pimSrc->m_sWinHeight;
  554. for (i=0;i<sNumFrames;i++,dCurDeg += dDegInc)
  555. {
  556. // Make a large enough vessel to rotate in:
  557. *(ppBuf.ppI) = new RImage;
  558. if ((*(ppBuf.ppI))->CreateImage(sDstH,sDstH,RImage::BMP8)!= SUCCESS)
  559. {
  560. TRACE("rspStrafeRotate: Out of memory. Sorry.\n");
  561. return -1;
  562. }
  563. // Do the BLiT:
  564. _RotateShrink(dCurDeg,pimSrc,(*ppBuf.ppI),0,0,sDstH,sDstH);
  565. // Get the coordinates:
  566. short sX=0,sY=0,sW=(short)(*(ppBuf.ppI))->m_sWidth,sH = (short)(*(ppBuf.ppI))->m_sHeight;
  567. rspLasso((UCHAR)0,(*(ppBuf.ppI)),sX,sY,sW,sH);
  568. rspCrop((*(ppBuf.ppI)),sX,sY,sW,sH);
  569. // Store the hot offset based on the center of the RotBuf:
  570. // Subtract this from your position..
  571. //
  572. *(pHotX.pL) = (sDstH>>1)-sX;
  573. *(pHotY.pL) = (sDstH>>1)-sY;
  574. // Dpo the links, if any:
  575. *(ppLinkX.ppL) = NULL;
  576. *(ppLinkY.ppL) = NULL;
  577. if (sNumLinks > 0)
  578. {
  579. *(ppLinkX.ppL) = (short*)calloc(sizeof(short),sNumLinks);
  580. *(ppLinkY.ppL) = (short*)calloc(sizeof(short),sNumLinks);
  581. double dRad = dCurDeg * 0.01745329251994;
  582. double dSin = sin(dRad)*scale;
  583. double dCos = cos(dRad)*scale;
  584. for (j=0;j<sNumLinks;j++)
  585. {
  586. (*(ppLinkX.ppL))[j] = (short)(dCos * psLinkX[j] - dSin * psLinkY[j]);
  587. (*(ppLinkY.ppL))[j] = (short)(dCos * psLinkY[j] + dSin * psLinkX[j]);
  588. }
  589. }
  590. // Convert to FSPR8:
  591. (*(ppBuf.ppI))->Convert(RImage::FSPR8);
  592. //----------------------------------------------------------------
  593. // move to the next element in the array:
  594. ppBuf.pB += lStructSize;
  595. pHotX.pB += lStructSize;
  596. pHotY.pB += lStructSize;
  597. ppLinkX.pB += lStructSize;
  598. ppLinkY.pB += lStructSize;
  599. }
  600. if (sNumLinks > 0)
  601. {
  602. free(psLinkX);
  603. free(psLinkY);
  604. }
  605. pimSrc->Convert((RImage::Type)ulOldType);
  606. return NULL;
  607. }