Rotate96.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  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. // This is one of the fist advanced BLiT functions supporting any color depth!
  19. #include "System.h"
  20. #ifdef PATHS_IN_INCLUDES
  21. #include "GREEN/BLiT/BLIT.H"
  22. #include "GREEN/BLiT/Cfnt.h"
  23. #include "ORANGE/QuickMath/Fractions.h"
  24. #else
  25. #include "BLIT.H"
  26. #include "Cfnt.h"
  27. #include "fractions.h"
  28. #endif
  29. #define _ROT64 // 64-bit math
  30. // This function will be made modular assuming the RSPiX inliner
  31. // will become a reality...
  32. //
  33. // For example, it will use the identical clipping and mirroring
  34. // technique that ScaleFlat96 used.
  35. //-------------------------------------------------------------------
  36. // DstW and DstH MUST be positive (not zero)!!!
  37. // This is POST CLIPPING, POST MIRRORING, POST PARAMETER VALIDATION!
  38. //
  39. inline void _BlitRot(short sDeg,short sHeight, // = 2R + 1?
  40. UCHAR* pSrcData,long lSrcXP,long lSrcP,
  41. UCHAR* pDstData,long lDstXP,long lDstP,
  42. short sDstW,short sDstH, // Target this for inlining!
  43. short sClipL,short sClipR,short sClipT,short sClipB)
  44. {
  45. // This algorithm uses 4 divisions per BLiT
  46. // Second order stuff...
  47. //--------------------------------------------------
  48. //----------- Initialize the large scale parameters:
  49. sDeg = rspMod360(sDeg);
  50. short sDegR = sDeg, sDegL = sDeg + 90, sDegP = sDeg + 225;
  51. // we know sDegV and sDeP must be positive, so don't do a full mod:
  52. while (sDegL > 359) sDegL -= 360; // FMOD/2
  53. while (sDegP > 359) sDegP -= 360; // FMOD/2
  54. //*************** Find P
  55. short sR = ( (sHeight-1) >> 1); // spinning corner radius
  56. short sEdge = short(sR * rspSQRT2); // square edge size
  57. // all things start at this source location:
  58. UCHAR* pP;
  59. long lDen = long(sDstW) * sDstH; // compound fraction
  60. // Calculate the sub pixel offset:
  61. long lLadNumX,lLadNumY,lRungNumX,lRungNumY;
  62. //**********************************************
  63. //****** OVERFLOW AREA - NEEDS 64bit math!
  64. //**********************************************
  65. // OVERFLOW LIMIT: lDstW * lDstH * sSrcW * sSrcH;
  66. // MUST CUSTOMIZE FOR THE MAC:
  67. #ifdef _ROT64
  68. // 64-bit version:
  69. S64 l64PX = S64(lDen) * sR,l64PY = S64(lDen) * sR; // go into Denominator space
  70. // Stay in denominator space!
  71. l64PX += S64(COSQ[sDegP] * sR * lDen + 0.5 * lDen); // offset to pixel center
  72. l64PY += S64(SINQ[sDegP] * sR * lDen + 0.5 * lDen); // offset to pixel center
  73. // Now MUST convert to an asymettrical signed proper fraction:
  74. long lPX,lPY;
  75. rspDivModA64(l64PX,lDen,lPX,lLadNumX);
  76. rspDivModA64(l64PY,lDen,lPY,lLadNumY);
  77. pP = pSrcData + lSrcXP * lPX + lSrcP * lPY;
  78. #else
  79. // 32-bit version
  80. long lPX = lDen * sR,lPY = lDen * sR; // go into Denominator space
  81. // Stay in denominator space!
  82. lPX += long(COSQ[sDegP] * sR * lDen + 0.5 * lDen); // offset to pixel center
  83. lPY += long(SINQ[sDegP] * sR * lDen + 0.5 * lDen); // offset to pixel center
  84. // Now MUST convert to an asymettrical signed proper fraction:
  85. rspDivModA64(lPX,lDen,lPX,lLadNumX);
  86. rspDivModA64(lPY,lDen,lPY,lLadNumY);
  87. pP = pSrcData + lSrcXP * lPX + lSrcP * lPY;
  88. #endif
  89. //**********************************************
  90. //--------------------------------------------------
  91. //--------- Initialize the four ratios...
  92. //
  93. // 1) Unnormalized ratios:
  94. //
  95. // Find the signed vector length of the rungs, in compound
  96. // fraction form...
  97. long lRungW = long(COSQ[sDegR] * sEdge * sDstH); // horizontal
  98. long lRungH = long(SINQ[sDegR] * sEdge * sDstH);
  99. long lLadW = long(COSQ[sDegL] * sEdge * sDstW); // vertical
  100. long lLadH = long(SINQ[sDegL] * sEdge * sDstW);
  101. // Convert from a point offset to true width and height:
  102. lRungW += SGN3(lRungW); // 3 phase sign
  103. lRungH += SGN3(lRungH); // 3 phase sign
  104. lLadW += SGN3(lLadW); // 3 phase sign
  105. lLadH += SGN3(lLadH); // 3 phase sign
  106. //
  107. // 2) Normalize the ratios if needed...
  108. //
  109. long lRungIncX = lRungW;
  110. long lRungIncY = lRungH;
  111. long lLadIncX = lLadW;
  112. long lLadIncY = lLadH;
  113. // General parameters:
  114. long lRungDelX=0,lRungDelY=0,lLadDelX=0,lLadDelY=0;
  115. // For now, only distinguish Rung IC, keep Ladder general:
  116. short sCondition = 0; // CONDITION FLAG
  117. #define sNegRungX 4
  118. #define sNegRungY 1
  119. #define sImproperRungX 8
  120. #define sImproperRungY 2
  121. #define sPosRungX 0
  122. #define sPosRungY 0
  123. #define sProperRungX 0
  124. #define sProperRungY 0
  125. // NOTE: ANSI does NOT define the sign of mod, but since the
  126. // denominator is ALWAYS positive, I can adjust for MOD issues...
  127. // The integral divisor is the same magnitude as the positive devisor
  128. //
  129. // FOR DELTA fractions, I will use a symmetric mod.
  130. // For COORDINATE fractions, I wil use an asymmetric mod:
  131. //
  132. //=========================== USE GENERAL IC for any case....
  133. if (ABS(lLadIncX) >= lDen)
  134. {
  135. DIV_MOD(lLadIncX,lDen,lLadDelX,lLadIncX);
  136. lLadDelX *= lSrcXP; // make the delta variables into screen space
  137. }
  138. if (ABS(lLadIncY) >= lDen)
  139. {
  140. DIV_MOD(lLadIncY,lDen,lLadDelY,lLadIncY);
  141. lLadDelY *= lSrcP; // make the delta variables into screen space
  142. }
  143. //============ DECIDE CHOICE FOR FUNCTION IC OVERLOAD ===========
  144. // Set of the Rung stuff for template IC overloading!
  145. if (lRungIncX <= 0) // negative increment
  146. {
  147. sCondition |= sNegRungX; // for IC function overload
  148. if (-lRungIncX >= lDen)
  149. {
  150. sCondition |= sImproperRungX; // for IC function overload
  151. DIV_MOD(lRungIncX,lDen,lRungDelX,lRungIncX);
  152. lRungDelX *= lSrcXP; // make the delta variables into screen space
  153. }
  154. }
  155. else // positive increment
  156. {
  157. if (lRungIncX >= lDen)
  158. {
  159. sCondition |= sImproperRungX; // for IC function overload
  160. DIV_MOD(lRungIncX,lDen,lRungDelX,lRungIncX);
  161. lRungDelX *= lSrcXP; // make the delta variables into screen space
  162. }
  163. }
  164. // Y component...
  165. if (lRungIncY <= 0) // negative increment
  166. {
  167. sCondition |= sNegRungY; // for IC function overload
  168. if (-lRungIncY >= lDen)
  169. {
  170. sCondition |= sImproperRungY; // for IC function overload
  171. DIV_MOD(lRungIncY,lDen,lRungDelY,lRungIncY);
  172. lRungDelY *= lSrcP; // make the delta variables into screen space
  173. }
  174. }
  175. else // positive increment
  176. {
  177. if (lRungIncY >= lDen)
  178. {
  179. sCondition |= sImproperRungY; // for IC function overload
  180. DIV_MOD(lRungIncY,lDen,lRungDelY,lRungIncY);
  181. lRungDelY *= lSrcP; // make the delta variables into screen space
  182. }
  183. }
  184. //==================================================================
  185. // relative to pP:
  186. long lLadX = 0,lLadY = 0,lRungX,lRungY;
  187. // test template, condition 0, no clip:
  188. UCHAR *pDst,*pDstLine = pDstData; // offset included for us...
  189. short i,j;
  190. // Left Top Clipping:
  191. // We can Top Left lip simply by moving the staring position
  192. // and reducing the width and height of the window:
  193. // 1) move up the ladder by sClipT:
  194. if (sClipT)
  195. {
  196. for (j = sClipT; j!=0; j--)
  197. {
  198. //-------------------- Advance the Ladder...
  199. // Use most general (slow) IC case...
  200. rspfrAdd32(lLadX,lLadNumX,lLadDelX,lLadIncX,lDen,lSrcXP);
  201. rspfrAdd32(lLadY,lLadNumY,lLadDelY,lLadIncY,lDen,lSrcP);
  202. pDstLine += lDstP;
  203. }
  204. sDstH -= sClipT;
  205. }
  206. // 2) move across the rung by sClipL:
  207. if (sClipL)
  208. {
  209. for (i = sClipL; i != 0; i--)
  210. {
  211. // Advance the Ladder in the rung direction...
  212. // Use general case for testing, then specific case later
  213. rspfrAdd32(lLadX,lLadNumX,lRungDelX,lRungIncX,lDen,lSrcXP);
  214. rspfrAdd32(lLadY,lLadNumY,lRungDelY,lRungIncY,lDen,lSrcP);
  215. pDstLine += lDstXP;
  216. }
  217. sDstW -= sClipL;
  218. }
  219. // Right Bottom Clipping: Easy
  220. sDstW -= sClipR;
  221. sDstH -= sClipB;
  222. for (j = sDstH; j!=0; j--)
  223. {
  224. //------------------- Set Rung to Ladder...
  225. pDst = pDstLine;
  226. lRungX = lLadX;
  227. lRungY = lLadY;
  228. lRungNumX = lLadNumX;
  229. lRungNumY = lLadNumY;
  230. //---------------------------------------------------------
  231. // Zeroth order stuff....
  232. PROPER proper = 0; // Value doesn't matter since var isn't REALLY used -- just want to avoid unitialized warning
  233. IMPROPER improper = 0; // Value doesn't matter since var isn't REALLY used -- just want to avoid unitialized warning
  234. POSITIVE positive = 0; // Value doesn't matter since var isn't REALLY used -- just want to avoid unitialized warning
  235. NEGATIVE negative = 0; // Value doesn't matter since var isn't REALLY used -- just want to avoid unitialized warning
  236. switch(sCondition)
  237. {
  238. UCHAR ucPix; // The only 8-bit concept:
  239. case (sProperRungX | sPosRungX | sProperRungY | sPosRungY):
  240. for (i = sDstW; i != 0; i--)
  241. {
  242. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  243. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, positive);
  244. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, positive);
  245. pDst += lDstXP;
  246. }
  247. break;
  248. case (sProperRungX | sPosRungX | sProperRungY | sNegRungY):
  249. for (i = sDstW; i != 0; i--)
  250. {
  251. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  252. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, positive);
  253. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, negative);
  254. pDst += lDstXP;
  255. }
  256. break;
  257. case (sProperRungX | sPosRungX | sImproperRungY | sPosRungY):
  258. for (i = sDstW; i != 0; i--)
  259. {
  260. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  261. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, positive);
  262. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, positive);
  263. pDst += lDstXP;
  264. }
  265. break;
  266. case (sProperRungX | sPosRungX | sImproperRungY | sNegRungY):
  267. for (i = sDstW; i != 0; i--)
  268. {
  269. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  270. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, positive);
  271. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, negative);
  272. pDst += lDstXP;
  273. }
  274. break;
  275. case (sProperRungX | sNegRungX | sProperRungY | sPosRungY):
  276. for (i = sDstW; i != 0; i--)
  277. {
  278. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  279. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, negative);
  280. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, positive);
  281. pDst += lDstXP;
  282. }
  283. break;
  284. case (sProperRungX | sNegRungX | sProperRungY | sNegRungY):
  285. for (i = sDstW; i != 0; i--)
  286. {
  287. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  288. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, negative);
  289. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, negative);
  290. pDst += lDstXP;
  291. }
  292. break;
  293. case (sProperRungX | sNegRungX | sImproperRungY | sPosRungY):
  294. for (i = sDstW; i != 0; i--)
  295. {
  296. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  297. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, negative);
  298. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, positive);
  299. pDst += lDstXP;
  300. }
  301. break;
  302. case (sProperRungX | sNegRungX | sImproperRungY | sNegRungY):
  303. for (i = sDstW; i != 0; i--)
  304. {
  305. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  306. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, proper, negative);
  307. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, negative);
  308. pDst += lDstXP;
  309. }
  310. break;
  311. case (sImproperRungX | sPosRungX | sProperRungY | sPosRungY):
  312. for (i = sDstW; i != 0; i--)
  313. {
  314. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  315. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, positive);
  316. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, positive);
  317. pDst += lDstXP;
  318. }
  319. break;
  320. case (sImproperRungX | sPosRungX | sProperRungY | sNegRungY):
  321. for (i = sDstW; i != 0; i--)
  322. {
  323. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  324. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, positive);
  325. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, negative);
  326. pDst += lDstXP;
  327. }
  328. break;
  329. case (sImproperRungX | sPosRungX | sImproperRungY | sPosRungY):
  330. for (i = sDstW; i != 0; i--)
  331. {
  332. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  333. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, positive);
  334. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, positive);
  335. pDst += lDstXP;
  336. }
  337. break;
  338. case (sImproperRungX | sPosRungX | sImproperRungY | sNegRungY):
  339. for (i = sDstW; i != 0; i--)
  340. {
  341. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  342. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, positive);
  343. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, negative);
  344. pDst += lDstXP;
  345. }
  346. break;
  347. case (sImproperRungX | sNegRungX | sProperRungY | sPosRungY):
  348. for (i = sDstW; i != 0; i--)
  349. {
  350. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  351. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, negative);
  352. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, positive);
  353. pDst += lDstXP;
  354. }
  355. break;
  356. case (sImproperRungX | sNegRungX | sProperRungY | sNegRungY):
  357. for (i = sDstW; i != 0; i--)
  358. {
  359. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  360. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, negative);
  361. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, proper, negative);
  362. pDst += lDstXP;
  363. }
  364. break;
  365. case (sImproperRungX | sNegRungX | sImproperRungY | sPosRungY):
  366. for (i = sDstW; i != 0; i--)
  367. {
  368. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  369. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, negative);
  370. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, positive);
  371. pDst += lDstXP;
  372. }
  373. break;
  374. case (sImproperRungX | sNegRungX | sImproperRungY | sNegRungY):
  375. for (i = sDstW; i != 0; i--)
  376. {
  377. ucPix = *(pP + lRungX + lRungY);if (ucPix) *pDst = ucPix;
  378. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP, improper, negative);
  379. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP, improper, negative);
  380. pDst += lDstXP;
  381. }
  382. break;
  383. }
  384. /*
  385. for (i = sDstW; i != 0; i--)
  386. {
  387. // The only 8-bit concept:
  388. UCHAR ucPix;
  389. ucPix = *(pP + lRungX + lRungY); // pitch included!
  390. if (ucPix) *pDst = ucPix;
  391. //------------------ Advance the rung...
  392. // Use general case for testing, then specific case later
  393. rspfrAdd32(lRungX,lRungNumX,lRungDelX,lRungIncX,lDen,lSrcXP);
  394. rspfrAdd32(lRungY,lRungNumY,lRungDelY,lRungIncY,lDen,lSrcP);
  395. pDst += lDstXP;
  396. }
  397. */
  398. //---------------------------------------------------------
  399. //-------------------- Advance the Ladder...
  400. // Use most general (slow) IC case...
  401. rspfrAdd32(lLadX,lLadNumX,lLadDelX,lLadIncX,lDen,lSrcXP);
  402. rspfrAdd32(lLadY,lLadNumY,lLadDelY,lLadIncY,lDen,lSrcP);
  403. pDstLine += lDstP;
  404. }
  405. }
  406. // With the inliner, this may become a very valuable tool.
  407. // This only performs DESTINATION CLIPPING AND MIRRORING..
  408. //
  409. // returns -1 if clipped out
  410. // returns 0 if shows at all
  411. // if (sClipL), use an HCLIP routine!
  412. //
  413. // returns pDst and sClips based on mirroring...
  414. // does NOT currently check input parameters...
  415. //
  416. inline short rspClipMirrorDst(RImage* pimDst, // input:
  417. short sClipX, // MUST be set
  418. short sClipY,
  419. short sClipW,
  420. short sClipH,
  421. short &sDstX, // Input AND output:
  422. short &sDstY,
  423. short &sDstW, // Negative for mirror
  424. short &sDstH, // Negative for mirror
  425. UCHAR* &pDst, // OUTPUT:
  426. short &sClipL, // positive = clip...
  427. short &sClipR,
  428. short &sClipT,
  429. short &sClipB,
  430. long &lDstP, // Including mirroring
  431. long &lDstPX // Incl. Mirroring & pixDepth
  432. )
  433. {
  434. short sMirrorX = 1,sMirrorY = 1; // direction flags...
  435. //********************* MIRROR PART I => PRE CLIP:
  436. lDstP = pimDst->m_lPitch;
  437. lDstPX = (pimDst->m_sDepth>>8);
  438. if (sDstW < 0)
  439. {
  440. sMirrorX = -1; // flip the destination square's edges...
  441. sDstW = -sDstW;
  442. sDstX -= (sDstW - 1);
  443. lDstPX = -lDstPX;
  444. }
  445. if (sDstH < 0)
  446. {
  447. sMirrorY = -1; // flip the destination square's edges...
  448. sDstH = -sDstH;
  449. sDstY -= (sDstH - 1);
  450. lDstP = -lDstP;
  451. }
  452. //-------- Do the clipping:
  453. sClipL = sClipX - sDstX; if (sClipL < 0) sClipL = 0;
  454. sClipT = sClipY - sDstY; if (sClipT < 0) sClipT = 0;
  455. sClipR = (sDstX + sDstW - sClipX - sClipW); if (sClipR < 0) sClipR = 0;
  456. sClipB = (sDstY + sDstH - sClipY - sClipH); if (sClipB < 0) sClipB = 0;
  457. if ( ((sClipL + sClipR) >= sDstW) || ((sClipT + sClipB) >= sDstH) )
  458. {
  459. return -1; // fully clipped out
  460. }
  461. //********************* MIRROR PART II => POST CLIP, flip back...
  462. if (sMirrorX == -1)
  463. {
  464. sDstX += (sDstW - 1);
  465. SWAP(sClipL,sClipR); // the drawing order is reversed...
  466. }
  467. if (sMirrorY == -1)
  468. {
  469. sDstY += (sDstH - 1);
  470. SWAP(sClipT,sClipB); // the drawing order is reversed...
  471. }
  472. // Use original pitch signs for offsets...
  473. pDst = pimDst->m_pData + pimDst->m_lPitch * sDstY + sDstX;
  474. return 0;
  475. }
  476. // Will allocate a larger buffer and copy the image so that it
  477. // can be rotated about the center (sHotX,sHotY).
  478. // m_lXPos and m_lYPos will point to the moved origin of the
  479. // RImage
  480. //
  481. short rspAddRotationPadding(RImage* pimSrc,short sHotX,short sHotY)
  482. {
  483. #ifdef _DEBUG
  484. // Check to make sure this is at least possibly correct styled assets..
  485. if (!pimSrc)
  486. {
  487. TRACE("rspAddRotationPadding: Null input images!\n");
  488. return -1;
  489. }
  490. // do type checking....
  491. //------------------------------------------------------------------------------
  492. if (!ImageIsUncompressed(pimSrc->m_type))
  493. {
  494. TRACE("rspAddRotationPadding: Only use this function with uncompressed Images.\n");
  495. return -1;
  496. }
  497. //------------------------------------------------------------------------------
  498. // do depth checking...
  499. //------------------------------------------------------------------------------
  500. if ((pimSrc->m_sDepth != 8))
  501. {
  502. TRACE("rspAddRotationPadding: Currently, only 8-bit Images are fully supported.\n");
  503. return -1;
  504. }
  505. if (pimSrc->m_sWinX || pimSrc->m_sWinY)
  506. {
  507. TRACE("rspAddRotationPadding: This image already has padding of some kind!\n");
  508. return -1;
  509. }
  510. #endif
  511. // Calculate maximum radius needed for a rotating square about the
  512. // center encapsulating the entire image...
  513. //
  514. long lR=0; // squared at first...
  515. long lHotXS = SQR((long)sHotX);
  516. long lHotYS = SQR((long)sHotY);
  517. // The radius will also equal the center of the buffer, and the buffer
  518. // size will be 2R+1 to deal with the half pixel buffer on all sides.
  519. //
  520. lR = MAX(lR,(long)SQR((long)sHotX - (pimSrc->m_sWidth - 1) ) +
  521. (long)SQR((long)sHotY - (pimSrc->m_sHeight - 1) ) ); // LR corner
  522. lR = MAX(lR,lHotXS + (long)SQR((long)sHotY - (pimSrc->m_sHeight - 1) ) ); // UR corner
  523. lR = MAX(lR,SQR(sHotX - (pimSrc->m_sWidth - 1) ) + lHotYS ); // LL corner
  524. lR = MAX(lR,lHotXS + lHotYS ); // UL corner
  525. lR = long(0.999999 + sqrt(double(lR) * 2.0)); // round up
  526. // The sqrt2 factor is needed because the moving window must enclose the circle.
  527. short sSize = short(1 + (lR << 1) ); // buffer = 2R + 1
  528. // Calculate new position of image within the buffer:
  529. short sX = short (lR - sHotX); // new offset...
  530. short sY = short (lR - sHotY);
  531. short sOldW = pimSrc->m_sWidth;
  532. short sOldH = pimSrc->m_sHeight;
  533. rspPad(pimSrc,sX,sY,sSize,sSize,1); // go to 8-bit alignment since offset may not align
  534. return 0;
  535. }
  536. // This uses the built in image description of padding.
  537. // This should really be a part of RImage.
  538. // This function currently only supports 8bit, uncompressed images..
  539. //
  540. short rspRemovePadding(RImage* pimSrc)
  541. {
  542. #ifdef _DEBUG
  543. // Check to make sure this is at least possibly correct styled assets..
  544. if (!pimSrc)
  545. {
  546. TRACE("rspRemovePadding: Null input images!\n");
  547. return -1;
  548. }
  549. // do type checking....
  550. //------------------------------------------------------------------------------
  551. if (!ImageIsUncompressed(pimSrc->m_type))
  552. {
  553. TRACE("rspRemovePadding: Only use this function with uncompressed Images.\n");
  554. return -1;
  555. }
  556. //------------------------------------------------------------------------------
  557. // do depth checking...
  558. //------------------------------------------------------------------------------
  559. if ((pimSrc->m_sDepth != 8))
  560. {
  561. TRACE("rspRemovePadding: Currently, only 8-bit Images are fully supported.\n");
  562. return -1;
  563. }
  564. #endif
  565. if (!pimSrc->m_sWinX && !pimSrc->m_sWinY)
  566. {
  567. // Don't need to do anything
  568. return 0;
  569. }
  570. // Create a new buffer and Image Stub to BLiT can use it:
  571. RImage imDst;
  572. long lNewPitch = (pimSrc->m_sWinWidth + 15) & ~15; // 128 bit align it
  573. imDst.CreateImage(pimSrc->m_sWinWidth,pimSrc->m_sWinHeight,pimSrc->m_type,
  574. lNewPitch,pimSrc->m_sDepth);
  575. // 3) Copy the new one in...
  576. rspBlit(pimSrc,&imDst,pimSrc->m_sWinX,pimSrc->m_sWinY,0,0,
  577. pimSrc->m_sWinWidth,pimSrc->m_sWinHeight);
  578. // tricky part: Swap buffers...
  579. UCHAR *pSrcMem,*pSrcBuf;
  580. pimSrc->DetachData((void**)&pSrcMem,(void**)&pSrcBuf);
  581. // Move the new buffer back to the original
  582. imDst.DetachData((void**)&(pimSrc->m_pMem),(void**)&(pimSrc->m_pData));
  583. //******* IMPORTANT! COPY ALL NEW INFO OVER!
  584. pimSrc->m_ulSize = imDst.m_ulSize;
  585. pimSrc->m_sWidth = imDst.m_sWidth; // width and height shouldn't change...
  586. pimSrc->m_sHeight = imDst.m_sHeight;
  587. pimSrc->m_lPitch = imDst.m_lPitch;
  588. pimSrc->m_sWinX = 0;
  589. pimSrc->m_sWinY = 0;
  590. // 4) Destroy the old...
  591. RImage::DestroyDetachedData((void**)&pSrcMem);
  592. // On exit, imDst will auto destruct....
  593. return 0;
  594. }
  595. // Assumes you are inputing the location of the center of rotation,
  596. // which is, in reality, the exact center of the buffered source
  597. // image.
  598. //
  599. short rspBlitRot(short sDeg,RImage* pimSrc,RImage* pimDst,
  600. short sDstX,short sDstY,short sDstW,short sDstH,
  601. const RRect* prDstClip)
  602. {
  603. #ifdef _DEBUG
  604. // Check to make sure this is at least possibly correct styled assets..
  605. if (!pimSrc || !pimDst)
  606. {
  607. TRACE("rspBlitRot: Null input images!\n");
  608. return -1;
  609. }
  610. // do type checking....
  611. //------------------------------------------------------------------------------
  612. if (!ImageIsUncompressed(pimSrc->m_type))
  613. {
  614. TRACE("rspBlitT: Only use this function with uncompressed Images.\n");
  615. return -1;
  616. }
  617. if (!ImageIsUncompressed(pimDst->m_type))
  618. {
  619. TRACE("rspBlitT: Only use this function with uncompressed Images.\n");
  620. return -1;
  621. }
  622. //------------------------------------------------------------------------------
  623. // do depth checking...
  624. //------------------------------------------------------------------------------
  625. if ((pimSrc->m_sDepth != 8) || (pimDst->m_sDepth != 8))
  626. {
  627. TRACE("rspBlitT: Currently, only 8-bit Images are fully supported.\n");
  628. return -1;
  629. }
  630. if (!pimSrc->m_sWinX || !pimSrc->m_sWinY)
  631. {
  632. TRACE("rspBlitRot: You must add buffer padding to the source image!\n");
  633. return -1;
  634. }
  635. #endif
  636. //------------------------------------------------------------------------------
  637. // do optional destination clipping
  638. //------------------------------------------------------------------------------
  639. // Destination clippiong rectangle:
  640. // NOTE: effective destination clipping done at a lower level.
  641. // Only source clipping would effect this...
  642. //
  643. short sDstClipX = 0, sDstClipY = 0;
  644. short sDstClipW = pimDst->m_sWidth, sDstClipH = pimDst->m_sHeight;
  645. // Suck it out!
  646. if (prDstClip)
  647. {
  648. sDstClipX = prDstClip->sX;
  649. sDstClipY = prDstClip->sY;
  650. sDstClipW = prDstClip->sW;
  651. sDstClipH = prDstClip->sH;
  652. }
  653. //********************* MIRROR PART I => PRE CLIP:
  654. // Instead of mirror FLAGS, make use of the destination pitch:
  655. //
  656. long lDstP = pimDst->m_lPitch,lDstXP = (pimDst->m_sDepth>>3);
  657. short sMirrorH = 1,sMirrorV = 1;
  658. if (sDstW < 0)
  659. {
  660. sMirrorH = -1; // flip the destination square's edges...
  661. sDstW = -sDstW;
  662. sDstX -= (sDstW - 1);
  663. lDstXP = -lDstXP;
  664. }
  665. if (sDstH < 0)
  666. {
  667. sMirrorV = -1; // flip the destination square's edges...
  668. sDstH = -sDstH;
  669. sDstY -= (sDstH - 1);
  670. lDstP = -lDstP;
  671. }
  672. //*********************
  673. //-------- Do the clipping:
  674. short sClipL,sClipR,sClipT,sClipB; // positive = clipped
  675. sClipL = sDstClipX - sDstX; if (sClipL < 0) sClipL = 0;
  676. sClipT = sDstClipY - sDstY; if (sClipT < 0) sClipT = 0;
  677. sClipR = (sDstX + sDstW - sDstClipX - sDstClipW); if (sClipR < 0) sClipR = 0;
  678. sClipB = (sDstY + sDstH - sDstClipY - sDstClipH); if (sClipB < 0) sClipB = 0;
  679. if ( ((sClipL + sClipR) >= sDstW) || ((sClipT + sClipB) >= sDstH) )
  680. {
  681. return 0; // fully clipped out
  682. }
  683. //********************* MIRROR PART II => POST CLIP, flip back...
  684. if (sMirrorH == -1)
  685. {
  686. sDstX += (sDstW - 1);
  687. SWAP(sClipL,sClipR); // the drawing order is reversed...
  688. }
  689. if (sMirrorV == -1)
  690. {
  691. sDstY += (sDstH - 1);
  692. SWAP(sClipT,sClipB); // the drawing order is reversed...
  693. }
  694. //*********************
  695. //------------------------------------------------------------------------------
  696. // set up IC
  697. //------------------------------------------------------------------------------
  698. // Use the old pitch because the coordinates have been changed
  699. UCHAR* pDst = pimDst->m_pData + pimDst->m_lPitch * sDstY + sDstX;
  700. // There is NO source position or source clipping here!
  701. UCHAR* pSrc = pimSrc->m_pData;
  702. // pass the mirrored pitches....
  703. _BlitRot(sDeg,pimSrc->m_sHeight,pSrc,pimSrc->m_sDepth>>3,pimSrc->m_lPitch,
  704. pDst,lDstXP,lDstP,sDstW,sDstH,sClipL,sClipR,sClipT,sClipB);
  705. return 0;
  706. }
  707. // Assumes you are inputing the location of the center of rotation,
  708. // which is, in reality, the exact center of the buffered source
  709. // image.
  710. // The scale is in terms of the source image, i.e. (1.0,1.0) = actual size
  711. // Negative values mirror!
  712. //
  713. short rspBlitRot(short sDeg,RImage* pimSrc,RImage* pimDst,
  714. short sDstX,short sDstY,double dScaleX,double dScaleY,
  715. const RRect* prDstClip)
  716. {
  717. short sDstW,sDstH;
  718. #ifdef _DEBUG // Do the minimum redundant validation necessary:
  719. // Check to make sure this is at least possibly correct styled assets..
  720. if (!pimSrc || !pimDst)
  721. {
  722. TRACE("rspBlitRot: Null input images!\n");
  723. return -1;
  724. }
  725. #endif
  726. // Calculate the true dimensions.
  727. // This occurs when DstW = EdgeW
  728. short sR = ( (pimSrc->m_sHeight-1) >> 1); // spinning corner radius
  729. short sEdge = short(sR * rspSQRT2); // square edge size
  730. sDstW = short(dScaleX * sEdge);
  731. sDstH = short(dScaleY * sEdge);
  732. return rspBlitRot(sDeg,pimSrc,pimDst,sDstX,sDstY,sDstW,sDstH,prDstClip);
  733. }
  734. //**************************************************************
  735. //*** BECAUSE THE OLD SrafeRot used GENERIC input structures
  736. //*** to hold the auxiliary data, it should still be useful!
  737. //**************************************************************
  738. // In this version, You must supply the host structure, which you may define, but which
  739. // must contain the following:
  740. //
  741. // NOTE: StrafeRotate has been made backwards compatible in two ways:
  742. // 1) it will AGAIN default to using a "CSTRAFE" output structure
  743. // 2) Degrees will be CLOCKWISE, and the offsets will be HOTSPOT convention.
  744. //
  745. short rspStrafeRotate(void *pReturnArray, // Output
  746. RImage* pimSrc,short sCenterX,short sCenterY,double dScale, // Input
  747. short sNumFrames,double dStartDeg,double dDegInc,
  748. short sNumLinks,short *psX,short *psY, // input
  749. // generic user stucture must be an array:
  750. RImage* pIm, short *psHotX, short *psHotY,
  751. short **ppsX,short **ppsY,
  752. long lStructSize)
  753. {
  754. #ifdef _DEBUG
  755. if (!pimSrc)
  756. {
  757. TRACE("rspStrafeRotate: NULL source passed!\n");
  758. return -1;
  759. }
  760. if (!pReturnArray)
  761. {
  762. TRACE("rspStrafeRotate: NULL receiver passed!\n");
  763. return -1;
  764. }
  765. if (sNumFrames < 1)
  766. {
  767. TRACE("rspStrafeRotate: Bad number of frames!\n");
  768. return -1;
  769. }
  770. if (!ImageIsUncompressed(pimSrc->m_type))
  771. {
  772. TRACE("rspStrafeRotate:Need an uncompressed image format!\n");
  773. return -1;
  774. }
  775. #endif
  776. union { short *pL; UCHAR *pB; } pHotX,pHotY;
  777. union { short **ppL; UCHAR *pB; } ppLinkX,ppLinkY;
  778. union { RImage **ppI; UCHAR *pB; } ppBuf;
  779. // IN PREVIOUS VERSIONS, THE USER COULD NOT UINPUT VALUES,
  780. // And then I would fill in a CStrafe for them.
  781. // NOTE: The CStrafe structure is not OFFICIALLY supported by RSPiX
  782. // but I am offering backwards compatibility for now...
  783. if (!pIm) ppBuf.ppI = &(((CStrafe*)pReturnArray)->pImage);
  784. if (!psHotX) pHotX.pL = &((CStrafe*)pReturnArray)->sHotX;
  785. if (!psHotY) pHotY.pL = &((CStrafe*)pReturnArray)->sHotY;
  786. if (!ppsX) ppLinkX.ppL = &((CStrafe*)pReturnArray)->psLinkX;
  787. if (!ppsY) ppLinkY.ppL = &((CStrafe*)pReturnArray)->psLinkY;
  788. double dCurDeg = dStartDeg;
  789. // calculate degree increment in default case:
  790. if (dDegInc == 0.0) dDegInc = 360.0 / (double)sNumFrames;
  791. // Phase one: make the source ROTBUF, and create a destination
  792. rspAddRotationPadding(pimSrc,sCenterX,sCenterY);
  793. short sSrcH = pimSrc->m_sHeight; // used for making a copy
  794. short sDstH = (sSrcH * dScale); // used for making a copy
  795. // Make a copy of the input links so they can be center adjusted
  796. short *psLinkX = NULL, *psLinkY = NULL;
  797. short j;
  798. if (sNumLinks > 0)
  799. {
  800. psLinkX = (short*)calloc(sizeof(short),sNumLinks);
  801. psLinkY = (short*)calloc(sizeof(short),sNumLinks);
  802. for (j=0;j<sNumLinks;j++)
  803. {
  804. psLinkX[j] = psX[j] - sCenterX;
  805. psLinkY[j] = psY[j] - sCenterY;
  806. }
  807. }
  808. // DO the strafing:
  809. short i;
  810. for (i=0;i<sNumFrames;i++,dCurDeg += dDegInc)
  811. {
  812. // Make a large enough vessel to rotate in:
  813. *(ppBuf.ppI) = new RImage;
  814. if ((*(ppBuf.ppI))->CreateImage(sDstH,sDstH,RImage::BMP8)!= SUCCESS)
  815. {
  816. TRACE("rspStrafeRotate: Out of memory. Sorry.\n");
  817. return -1;
  818. }
  819. // Do the BLiT such that the hot spot is in the center of the buffer:
  820. //_RotateShrink(dCurDeg,pimSrc,(*ppBuf.ppI),0,0,sDstH,sDstH);
  821. // CREATE A CLOCKWISE SENSE:
  822. rspBlitRot(short(360.0 - dCurDeg),pimSrc,(*ppBuf.ppI),0,0,dScale,dScale);
  823. // Get the coordinates:
  824. short sX=0,sY=0,sW=(short)(*(ppBuf.ppI))->m_sWidth,sH = (short)(*(ppBuf.ppI))->m_sHeight;
  825. rspLasso((UCHAR)0,(*(ppBuf.ppI)),sX,sY,sW,sH);
  826. rspCrop((*(ppBuf.ppI)),sX,sY,sW,sH); // sX,sY are the blitting offset
  827. // Store the hot offset using the center of the RotBuf as origin
  828. // Subtract this from position you wish center to appear
  829. //
  830. *(pHotX.pL) = rspSQRT2 / 4. * sDstH - sX;
  831. *(pHotY.pL) = rspSQRT2 / 4. * sDstH - sY;
  832. // Dpo the links, if any:
  833. *(ppLinkX.ppL) = NULL;
  834. *(ppLinkY.ppL) = NULL;
  835. if (sNumLinks > 0)
  836. {
  837. *(ppLinkX.ppL) = (short*)calloc(sizeof(short),sNumLinks);
  838. *(ppLinkY.ppL) = (short*)calloc(sizeof(short),sNumLinks);
  839. //double dRad = dCurDeg * 0.01745329251994;
  840. short sCurDeg = short(dCurDeg); // CLOCKWISE SENSE
  841. sCurDeg = rspMod360(sCurDeg);
  842. double dSin = SINQ[sCurDeg]*dScale;
  843. double dCos = COSQ[sCurDeg]*dScale;
  844. for (j=0;j<sNumLinks;j++)
  845. {
  846. (*(ppLinkX.ppL))[j] = (short)(dCos * psLinkX[j] - dSin * psLinkY[j]);
  847. (*(ppLinkY.ppL))[j] = (short)(dCos * psLinkY[j] + dSin * psLinkX[j]);
  848. }
  849. }
  850. // Convert to FSPR8:
  851. (*(ppBuf.ppI))->Convert(RImage::FSPR8);
  852. //----------------------------------------------------------------
  853. // move to the next element in the array:
  854. ppBuf.pB += lStructSize;
  855. pHotX.pB += lStructSize;
  856. pHotY.pB += lStructSize;
  857. ppLinkX.pB += lStructSize;
  858. ppLinkY.pB += lStructSize;
  859. }
  860. if (sNumLinks > 0)
  861. {
  862. free(psLinkX);
  863. free(psLinkY);
  864. }
  865. // Restore the source picture to it's original form.
  866. rspRemovePadding(pimSrc);
  867. return NULL;
  868. }
  869. //**************************************************************