FSPR8.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  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. //********************************************
  19. // Here is the basic FSPR8 IO, Convert, & BLiT
  20. //********************************************
  21. #include "System.h"
  22. #ifdef PATHS_IN_INCLUDES
  23. #include "GREEN/BLiT/BLIT.H"
  24. #include "GREEN/BLiT/_BlitInt.H"
  25. #include "ORANGE/QuickMath/Fractions.h"
  26. #include "GREEN/Image/SpecialTyp.h"
  27. #else
  28. #include "BLIT.H"
  29. #include "_BlitInt.H"
  30. #include "Fractions.h"
  31. #include "specialtyp.h"
  32. #endif
  33. #include <string.h>
  34. //***************************************************************************
  35. // NOTES: The FSPR8 compression format is NOT based around the idea of
  36. // data compression, but around the sheer speed of assembly blitting.
  37. // In short, the compression op codes are designed to have the fastest
  38. // decoding possible. In emprical testing, this FSP8 format outperformed
  39. // five other more "advanced" algorithms which took longer to read their
  40. // OP-CODES. It provides semi-random access by compressing scan lines as
  41. // autonomous units, which makes things like clipping much, much faster.
  42. //***************************************************************************
  43. // There is currently no convert options for FSPR8.
  44. // Color index zero is transparancy. Mild performance degredation may occur
  45. // for objects with visual details larger than 256 pixels across.
  46. //---------------- Predeclare linklate functions ---------------------------
  47. short DeleteFSPR8(RImage* pImage);
  48. short ConvertToFSPR8(RImage* pImage);
  49. short ConvertFromFSPR8(RImage* pImage);
  50. short LoadFSPR8(RImage* pImage, RFile* pcf);
  51. short SaveFSPR8(RImage* pImage, RFile* pcf);
  52. //---------------- EXTRA Conversion Information ----------------------------
  53. // Currently none.
  54. //------------------- HOOK into the CImage world ------------------------
  55. IMAGELINKLATE(FSPR8,ConvertToFSPR8,ConvertFromFSPR8,
  56. LoadFSPR8,SaveFSPR8,NULL,DeleteFSPR8);
  57. //------------------------------------------------------------------------
  58. short DeleteFSPR8(RImage* pImage)
  59. {
  60. if (pImage->m_pSpecial != NULL)
  61. {
  62. delete (RSpecialFSPR8*) pImage->m_pSpecial;
  63. }
  64. return SUCCESS;
  65. }
  66. //------------------------------------------------------------------------
  67. // SAVES ONLY the pSpecial information!
  68. //
  69. short SaveFSPR8(RImage* pImage, RFile* pcf)
  70. {
  71. // Assume valid pImage and cnfile:
  72. RSpecialFSPR8* pSpec = (RSpecialFSPR8*) pImage->m_pSpecialMem;
  73. if (!pSpec)
  74. {
  75. TRACE("Save FSPR8: Bad FSPR8!\n");
  76. return -1;
  77. }
  78. //------------------
  79. // Initial Security:
  80. //------------------
  81. pcf->Write("__FSPR8__"); // image type
  82. U16 version = (U16)(6); // Sprite incarnation 3, File Format 5
  83. pcf->Write(&version);
  84. //------------------
  85. // Info
  86. //------------------
  87. // NOTE: Some font info is stored here:
  88. pcf->Write((U16*)(&(pSpec->m_usSourceType)));
  89. pcf->Write(&(pSpec->m_lBufSize));
  90. pcf->Write(&(pSpec->m_lCodeSize));
  91. // Reserved for future expansion
  92. U32 reserved[4] = {0,0,0,0};
  93. pcf->Write(reserved,4); // 16 bytes reserved as of version 3.5
  94. // Write the pixel data:
  95. pcf->Write(pSpec->m_pCompBuf,pSpec->m_lBufSize);
  96. // Write the code data
  97. pcf->Write(pSpec->m_pCodeBuf,pSpec->m_lCodeSize);
  98. // Write the Line Array and Control array as 32-bit offsets:
  99. // Both are (H+1) long:
  100. short i;
  101. U32 lOffset;
  102. // Do pointers into pixel data:
  103. for (i=0;i <= pImage->m_sHeight;i++)
  104. {
  105. lOffset = U32(pSpec->m_pBufArry[i] - pSpec->m_pCompBuf);
  106. pcf->Write(&lOffset);
  107. }
  108. // Do pointers into control data:
  109. for (i=0;i <= pImage->m_sHeight;i++)
  110. {
  111. lOffset = U32(pSpec->m_pCodeArry[i] - pSpec->m_pCodeBuf);
  112. pcf->Write(&lOffset);
  113. }
  114. return SUCCESS;
  115. }
  116. //------------------------------------------------------------------------
  117. // Assumes all of the FSPR1 has successfully been
  118. // loaded EXCEPT for pSpecial[Mem]
  119. //
  120. short LoadFSPR8(RImage* pImage, RFile* pcf)
  121. {
  122. //------------------
  123. // Initial Security:
  124. //------------------
  125. char szTemp[10];
  126. pcf->Read(&szTemp[0]);
  127. // Check type:
  128. if (strcmp(szTemp,"__FSPR8__")) // not equal
  129. {
  130. TRACE("Load FSPR8: Not correct file type!\n");
  131. return -1;
  132. }
  133. // Check Version:
  134. U16 u16Temp;
  135. pcf->Read(&u16Temp);
  136. if (u16Temp != (6))
  137. {
  138. TRACE("Load FSPR8: This is an older FSPR8 format!\n");
  139. return -1;
  140. }
  141. //------------------
  142. // Info
  143. //------------------
  144. RSpecialFSPR8* pSpec = new RSpecialFSPR8;
  145. pImage->m_pSpecialMem = pImage->m_pSpecial = (UCHAR*)pSpec;
  146. pcf->Read((U16*)(&pSpec->m_usSourceType));
  147. pcf->Read(&pSpec->m_lBufSize);
  148. pcf->Read(&pSpec->m_lCodeSize);
  149. //-------- ALLOCATE THE FIELDS!!!
  150. // No alignment needed for 8-bit:
  151. pSpec->m_pCompMem = pSpec->m_pCompBuf = (UCHAR*)malloc(pSpec->m_lBufSize);
  152. pSpec->m_pCodeBuf = (UCHAR*)malloc(pSpec->m_lCodeSize);
  153. pSpec->m_pBufArry = (UCHAR**)malloc(sizeof(UCHAR*) * (pImage->m_sHeight+1));
  154. pSpec->m_pCodeArry = (UCHAR**)malloc(sizeof(UCHAR*) * (pImage->m_sHeight+1));
  155. //------------------
  156. // Reserved Space
  157. //------------------
  158. U32 u32Temp[4];
  159. pcf->Read(u32Temp,4); // 16 bytes reserved as of version 3.5
  160. //------------------
  161. // The Image Data
  162. //------------------
  163. // Now the actual data, which needs no alignment:
  164. // (Pre ALLOCATED)
  165. pcf->Read(pSpec->m_pCompBuf,pSpec->m_lBufSize);
  166. pcf->Read(pSpec->m_pCodeBuf,pSpec->m_lCodeSize);
  167. // Now restore the pointer list by adding them as offsets!
  168. // (Pre ALLOCATED!)
  169. short i;
  170. U32 lOffset;
  171. // Do pointers into pixel data:
  172. for (i=0;i <= pImage->m_sHeight;i++)
  173. {
  174. pcf->Read(&lOffset);
  175. pSpec->m_pBufArry[i] = pSpec->m_pCompBuf + lOffset;
  176. }
  177. // Do pointers into control data:
  178. for (i=0;i <= pImage->m_sHeight;i++)
  179. {
  180. pcf->Read(&lOffset);
  181. pSpec->m_pCodeArry[i] = pSpec->m_pCodeBuf + lOffset;
  182. }
  183. return SUCCESS;
  184. }
  185. //------------------------------------------------------------------------
  186. // Returns to previous 8-bit screen format:
  187. //
  188. short ConvertFromFSPR8(RImage* pImage)
  189. {
  190. // Assume it is of the correct format:
  191. if (pImage->m_type != RImage::FSPR8) return RImage::NOT_SUPPORTED;
  192. // Will try to restore the previous type of uncompressed, 8-bit buffer:
  193. // Generate a new buffer:
  194. // GuessAPitch
  195. pImage->m_lPitch = (pImage->m_sWidth + 15) & (~15); // 128 it!
  196. pImage->CreateData(pImage->m_lPitch * pImage->m_sHeight); // should be blank
  197. // BLiT Into the buffer!
  198. UCHAR* pDstLine = pImage->m_pData; // centered at 0,0
  199. UCHAR* pDst;
  200. short sY=0;
  201. RSpecialFSPR8* pInfo = (RSpecialFSPR8*) pImage->m_pSpecial;
  202. UCHAR ucCode;
  203. UCHAR* pSrc;
  204. UCHAR* pCB;
  205. for (sY = 0; sY < pImage->m_sHeight; sY++,pDstLine += pImage->m_lPitch)
  206. {
  207. pSrc = pInfo->m_pBufArry[sY];
  208. pDst = pDstLine;
  209. pCB = pInfo->m_pCodeArry[sY];
  210. NextCode3:
  211. //==============================================================
  212. // 1) Do the clear run:
  213. ucCode = *(pCB)++; // Get Skip Length
  214. if (ucCode == 255) continue;// End of line code
  215. pDst += ucCode; // Skip
  216. //==============================================================
  217. // 2) Do the opaque run:
  218. ucCode = *(pCB)++; // Get Skip Length
  219. if (!ucCode) goto NextCode3;
  220. do *(pDst++) = *(pSrc++); // Copy pixel
  221. while (--ucCode);
  222. goto NextCode3;
  223. }
  224. //==============================================================
  225. // Now finish your job:
  226. //
  227. pImage->m_type = (RImage::Type)pInfo->m_usSourceType; // Set back the type;
  228. // Remove pSpecial:
  229. delete (RSpecialFSPR8*) pImage->m_pSpecial;
  230. pImage->m_pSpecial = pImage->m_pSpecialMem = NULL;
  231. return (short)pImage->m_type;
  232. }
  233. //------------------------------------------------------------------------
  234. // Returns NOT_SUPPORTED if conversion is not possible:
  235. // Destroys the image's buffer (officially) and sets it to NULL
  236. //
  237. short ConvertToFSPR8(RImage* pImage)
  238. {
  239. // Convert to BKD8:
  240. #ifdef _DEBUG
  241. // Can convert any standard uncompressed 8-bit buffer....
  242. if (!ImageIsUncompressed(pImage->m_type))
  243. {
  244. TRACE("ConvertFSPR8: Can only compress an uncompressed image!\n");
  245. return RImage::NOT_SUPPORTED;
  246. }
  247. if (pImage->m_sDepth != 8)
  248. {
  249. TRACE("ConvertFSPR8: Can only compress an 8-bit image!\n");
  250. return RImage::NOT_SUPPORTED;
  251. }
  252. if (pImage->m_pData == NULL)
  253. {
  254. TRACE("Convert: Invalid image passed to convert to FSPR8\n");
  255. return RImage::NOT_SUPPORTED;
  256. }
  257. #endif
  258. //********************* DO THE CONVERSION ************************
  259. RSpecialFSPR8* pHeader = new RSpecialFSPR8;
  260. pHeader->m_usCompType = RImage::FSPR8;
  261. pHeader->m_usSourceType = (USHORT) pImage->m_type;
  262. //************ RUN LENGTH COMPRESSION -> 8-bit Aligned **********
  263. //====== CONTROL BLOCK CODES (8-bit) ====== (Only one run type)
  264. // if first clear run byte = 255, done the line
  265. // This is initial offset,
  266. //
  267. // Next byte = # of bytes to run with (opaque run) If the run is
  268. // >255 pixels, then you get a 0 for next clear run, then another
  269. // amt of run... This keeps max run to 255.
  270. //
  271. // if the clear run byte = 255, done line, else...repeat the concept...
  272. //===== Justification for continual ADDING... that so RARELY will a
  273. // space ever be more than 254 pixels wide
  274. //===== The compressed buffer:
  275. // This is an 8-aligned pixel buffer containing only opaque pixels
  276. //===== The m_pBufArry ... points at the start of each new line in the pixel array
  277. //===== The m_pCodeArry ... points to the start of each line in the control block.
  278. short x,y; // For now, clear = 0, but this can be EASILY changed.
  279. long i;
  280. short sCount;
  281. UCHAR *pucOldMem,*pucOldBuf; // For shrinking the buffer while maintaining alignment
  282. //********* MALLOC all elements to maximum possible length, then shrink them. (realloc)
  283. //********* for now, assume MALLOC returns 32-bit aligned ptr arrays.
  284. // Max memory requirements: Compresssed block = uncompressed block.
  285. // Control Block = (width+1)*height
  286. // m_pCodeArry always = m_pBufArry always = 4*height bytes.
  287. // So worst case scenario: MEM = Height * (2*Width+9)
  288. //*********************************** These are always the same size!
  289. // Adjustment... for saving and retrieval, I am storing the total buffer sizes
  290. // as the last elements in the random access arrays.
  291. //
  292. pHeader->m_pCodeArry = (UCHAR**)calloc(pImage->m_sHeight+1,sizeof(UCHAR*));
  293. pHeader->m_pBufArry = (UCHAR**)calloc(pImage->m_sHeight+1,sizeof(UCHAR*));
  294. //************** For now, set these to an optimisitically large size: 1:1 compression (could be 2:1 worst case)
  295. long lSizeEstimate = ((long)(pImage->m_sHeight+1))*(pImage->m_sWidth*2+1) + 15;
  296. pHeader->m_pCompMem = (UCHAR*)malloc((size_t)pImage->m_sHeight*(size_t)pImage->m_sWidth+15);
  297. pHeader->m_pCompBuf = (UCHAR*)(( (long)(pHeader->m_pCompMem) + 15) & ~ 15); // align it 128!
  298. pHeader->m_pCodeBuf = (UCHAR*)malloc((size_t)lSizeEstimate);
  299. //******** For convenience, generate the Compressed Buffer immediately:
  300. UCHAR* pucCPos = pHeader->m_pCompBuf;
  301. UCHAR* pucBPos = pImage->m_pData; // read the actual buffer
  302. short sW = pImage->m_sWidth;
  303. short sH = pImage->m_sHeight;
  304. short sP = pImage->m_lPitch;
  305. // WARNING: THIS IS HARD CODED 8-bit PIXEL SIZE STUFF!
  306. for (y=0;y<sH;y++)
  307. {
  308. pHeader->m_pBufArry[y] = (UCHAR*)(pucCPos - pHeader->m_pCompBuf); // set line pointer
  309. for (x=0,pucBPos = pImage->m_pData + (long)sP * (long)y; x<sW; x++)
  310. {
  311. if (*pucBPos != 0) *(pucCPos++) = *pucBPos;
  312. pucBPos++;
  313. }
  314. }
  315. // WARNING: ASSERTS WILL BE SCREWED UP BY NEGATIVE PITCH!
  316. ASSERT( ((pucCPos - pHeader->m_pCompBuf)) < 2*1024*1024); // just in case something flakey happens!
  317. ASSERT( ((pucCPos - pHeader->m_pCompBuf)) >= 0); // just in case something flakey happens!
  318. // NOTE THE SIZE:
  319. pHeader->m_lBufSize = ULONG(pucCPos - pHeader->m_pCompBuf);
  320. // Shrink the Compressed buffer:
  321. if (pucCPos == pHeader->m_pCompBuf)
  322. {
  323. TRACE("Convert to FSPR8: FATAL error. A blank buffer cannot be compressed.\n");
  324. delete pHeader;
  325. return RImage::NOT_SUPPORTED;
  326. }
  327. // The alignment will shift when the realloc blindly copied the memory. So, realloc is
  328. // nolonger feasible. I will take memory management into my own hands!
  329. //
  330. pucOldMem = pHeader->m_pCompMem;
  331. pucOldBuf = pHeader->m_pCompBuf;
  332. // create a new buffer of the appropriate size:
  333. // NOTE: pucCPos is an open stack!
  334. pHeader->m_pCompMem = (UCHAR*)calloc(1,(size_t)(pucCPos - pHeader->m_pCompBuf + 15));
  335. // And align it:
  336. pHeader->m_pCompBuf = (UCHAR*)(( (long)(pHeader->m_pCompMem) +15)&~15);
  337. // Store the size of the Compressed Buffer:
  338. pHeader->m_pBufArry[sH] = (UCHAR*)(size_t)(pucCPos - pHeader->m_pCompBuf);
  339. // Now copy the old into the new aligned and free it:
  340. for (i=0;i<pucCPos - pucOldBuf;i++) pHeader->m_pCompBuf[i] = pucOldBuf[i];
  341. free(pucOldMem);
  342. // Now update the indexes (m_pBufArry) which point into PCBuf:
  343. for (y=0;y<sH;y++) pHeader->m_pBufArry[y] += (long)(pHeader->m_pCompBuf);
  344. //******** NOW, the challange... Create the Control Block!
  345. pucBPos = pImage->m_pData;
  346. UCHAR* pucConBlk = pHeader->m_pCodeBuf;
  347. for (y=0;y<sH;y++)
  348. {
  349. pHeader->m_pCodeArry[y] = (UCHAR*)(pucConBlk - pHeader->m_pCodeBuf); // set Block pointer
  350. pucBPos = pImage->m_pData + (long)sP * (long)y;
  351. x=0;
  352. NextRun:
  353. // A> The CLEAR RUN
  354. // 1) Count clear space
  355. sCount = 0;
  356. while ((x<sW) && (*pucBPos == 0)) {x++;sCount++;pucBPos++;}
  357. if (x == sW) // you are at the end of the line!
  358. {
  359. *(pucConBlk++)=255; // end of line code
  360. continue; // goto next y-line
  361. }
  362. // 2) If count >254, back it up!
  363. if (sCount > 254)
  364. {
  365. pucBPos -= (sCount - 254);
  366. x -= (sCount - 254);
  367. sCount = 254;
  368. }
  369. // 3) place count into control block:
  370. *(pucConBlk++)=(UCHAR)sCount; // The Clear Run
  371. // B> The OPAQUE RUN
  372. // 1) Count opaque space
  373. sCount = 0;
  374. while ((x<sW) && (*pucBPos != 0)) {x++;sCount++;pucBPos++;}
  375. // 2) If count >255, back it up!
  376. if (sCount > 255)
  377. {
  378. pucBPos -= (sCount - 255);
  379. x -= (sCount - 255);
  380. sCount = 255;
  381. }
  382. // 3) place opaque count into control block:
  383. *(pucConBlk++)=(UCHAR)sCount; // The Clear Run
  384. if (x == sW) // you are at the end of the line!
  385. {
  386. *(pucConBlk++)=255; // end of line code
  387. continue; // goto next y-line
  388. }
  389. goto NextRun;
  390. }
  391. // Store the size of the Control Block Buffer:
  392. pHeader->m_pCodeArry[sH] = (UCHAR*)(size_t)(pucConBlk - pHeader->m_pCodeBuf);
  393. // NOTE THE SIZE:
  394. pHeader->m_lCodeSize = ULONG(pucConBlk - pHeader->m_pCodeBuf);
  395. // Shrink the Control Block buffer:
  396. pHeader->m_pCodeBuf = (UCHAR*)realloc((void*)pHeader->m_pCodeBuf,
  397. (size_t)(pucConBlk - pHeader->m_pCodeBuf));
  398. // Move the indexes in (m_pCodeArry)
  399. for (y=0;y<sH;y++) pHeader->m_pCodeArry[y] += (long)(pHeader->m_pCodeBuf);
  400. //******************************************************************
  401. //******************************************************************
  402. // Install the newly compressed buffer:
  403. // Kill the old buffer in an Image-Safe way:
  404. //pImage->DestroyData();
  405. void* pTempData = pImage->DetachData();
  406. RImage::DestroyDetachedData(&pTempData);
  407. pImage->m_pSpecial = (UCHAR*) pHeader; // Put the data in special.
  408. pImage->m_pSpecialMem = pImage->m_pSpecial; // So that our delete may be called!
  409. pImage->m_type = RImage::FSPR8;
  410. pImage->m_ulSize = 0; // BLiT needs to deal with copying, etc....
  411. return RImage::FSPR8;
  412. }
  413. //------------------------------------------------------------------------
  414. //***************************** THE FSPRITE BLiT ******************************
  415. // currently 8-bit, but soon to be full color.
  416. // Must deal with screen locking.
  417. //
  418. short rspBlit(RImage* pimSrc,RImage* pimDst,short sDstX,short sDstY,const RRect* prDst)
  419. {
  420. short sClip;
  421. // 1) preliminary parameter validation:
  422. #ifdef _DEBUG
  423. if ((pimSrc == NULL) || (pimDst == NULL))
  424. {
  425. TRACE("BLiT: null CImage* passed\n");
  426. return -1;
  427. }
  428. if ((!ImageIsUncompressed(pimDst->m_type)))
  429. {
  430. TRACE("BLiT: Cannot BLiT this into a compressed buffer!\n");
  431. return -1;
  432. }
  433. if ((pimSrc->m_type == RImage::FSPR16) || (pimSrc->m_type == RImage::FSPR32))
  434. {
  435. TRACE("BLiT: TC sprites are not YET implemented.\n");
  436. return -1;
  437. }
  438. if (pimSrc->m_type == RImage::FSPR1)
  439. {
  440. TRACE("BLiT: Use a different form of parameters for this type (see BLiT.DOC).\n");
  441. return -1;
  442. }
  443. #endif
  444. // HOOK special cases:
  445. if (ImageIsUncompressed(pimSrc->m_type)) // for now do an opaque BLiT!
  446. {
  447. // Doing a background BLiT for speed, although a BlitT is more desired
  448. rspBlit(pimSrc,pimDst,0,0,sDstX,sDstY,pimSrc->m_sWidth,pimSrc->m_sHeight,prDst);
  449. return 0;
  450. }
  451. // 2) Destination Clipping is hard here:
  452. short sClipL=0,sClipR=0,sClipT=0,sClipB=0;
  453. short sSrcX = 0,sSrcY = 0; // clippng parameters...
  454. short sW = pimSrc->m_sWidth; // clippng parameters...
  455. short sH = pimSrc->m_sHeight; // clippng parameters...
  456. long lDstP = pimDst->m_lPitch;
  457. if (prDst)
  458. {
  459. // clip against user values
  460. sClip = prDst->sX - sDstX; // positive = clipped
  461. if (sClip > 0) { sW -= sClip; sSrcX += sClip; sDstX = prDst->sX; }
  462. sClip = prDst->sY - sDstY; // positive = clipped
  463. if (sClip > 0) { sH -= sClip; sSrcY += sClip; sDstY = prDst->sY; }
  464. sClip = sDstX + sW - prDst->sX - prDst->sW; // positive = clipped
  465. if (sClip > 0) { sW -= sClip; }
  466. sClip = sDstY + sH - prDst->sY - prDst->sH; // positive = clipped
  467. if (sClip > 0) { sH -= sClip; }
  468. if ( (sW <= 0) || (sH <= 0) ) return -1; // clipped out!
  469. }
  470. else
  471. {
  472. // clip against full destination buffer
  473. if (sDstX < 0) { sW += sDstX; sSrcX -= sDstX; sDstX = 0; }
  474. if (sDstY < 0) { sH += sDstY; sSrcY -= sDstY; sDstY = 0; }
  475. sClip = sDstX + sW - pimDst->m_sWidth; // positive = clipped
  476. if (sClip > 0) sW -= sClip; // positive = clipped
  477. sClip = sDstY + sH - pimDst->m_sHeight; // positive = clipped
  478. if (sClip > 0) sH -= sClip; // positive = clipped
  479. if ((sW <= 0) || (sH <= 0)) return -1; // fully clipped
  480. }
  481. //************** INSERT BUFFER HOOKS HERE! ************************
  482. // do OS based copying!
  483. short sNeedToUnlock = 0; // will be the name of a buffer to unlock.
  484. short sBlitTypeDst = 0; // normal image:
  485. // IN RELEASE MODE, GIVE THE USER A CHANCE:
  486. #ifndef _DEBUG
  487. //if (gsScreenLocked || gsBufferLocked) goto BLIT_PRELOCKED;
  488. #endif
  489. // IN THIS IMPLEMENTATION, we must do LOCK, BLiT, UNLOCK, so I
  490. // must record which UNLOCK (if any) needs to be done AFTER the BLiT
  491. // has completed. (Lord help me if a blit gets interrupted)
  492. // NOT NECESSARY!!! THe SOURCE WILL ALWAYS BE A BUFFER!
  493. if (pimDst->m_type == RImage::IMAGE_STUB) sBlitTypeDst = (short)((long)pimDst->m_pSpecial);
  494. switch (sBlitTypeDst) // 0 = normal image
  495. {
  496. case BUF_MEMORY: // image to system buffer
  497. /*
  498. // need to lock / unlock this one:
  499. if (rspLockBuffer()
  500. !=0)
  501. {
  502. TRACE("BLiT: Unable to lock the system buffer, failed!\n");
  503. return -1;
  504. }
  505. // Locked the system buffer, remember to unlock it:
  506. sNeedToUnlock = BUF_MEMORY;
  507. */
  508. break;
  509. case BUF_VRAM: // image to front screen
  510. /*
  511. // need to lock / unlock this one:
  512. if (rspLockScreen()
  513. !=0)
  514. {
  515. TRACE("BLiT: Unable to lock the OnScreen system buffer, failed!\n");
  516. return -1;
  517. }
  518. // Locked the front VRAM, remember to unlock it:
  519. sNeedToUnlock = BUF_VRAM;
  520. */
  521. break;
  522. case BUF_VRAM2: // image to back screen
  523. // need to lock / unlock this one:
  524. if (rspLockVideoFlipPage((void**)&(pimDst->m_pData),&(pimDst->m_lPitch))
  525. !=0)
  526. {
  527. TRACE("BLiT: Unable to lock the OffScreen system buffer, failed!\n");
  528. return -1;
  529. }
  530. // Locked the front VRAM, remember to unlock it:
  531. sNeedToUnlock = BUF_VRAM;
  532. break;
  533. case 0: // image to image
  534. sNeedToUnlock = 0; // no unlock!
  535. break;
  536. default:
  537. TRACE("BLiT: This type of copy is not yet supported.\n");
  538. return -1;
  539. }
  540. //BLIT_PRELOCKED:
  541. //*******************************************************************
  542. // 8-bit biased!
  543. // Check for locking error:
  544. if (!pimDst->m_pData)
  545. {
  546. TRACE("BLiT: NULL data - possible bad lock.\n");
  547. return FALSE;
  548. }
  549. // Right now, pDst refers to the CLIPPED start of the scanline:
  550. UCHAR* pDstLine = pimDst->m_pData + sDstX + sDstY * pimDst->m_lPitch;
  551. UCHAR* pDst;
  552. short sY=0;
  553. RSpecialFSPR8* pInfo = (RSpecialFSPR8*) pimSrc->m_pSpecial;
  554. UCHAR ucCode;
  555. UCHAR* pSrc;
  556. UCHAR* pCB;
  557. short sClipWidth;
  558. //
  559. if (sSrcX > 0) // LClip Situation! => The slowest!
  560. {
  561. //**** THE WORST OF ALL CASES! TWO SIDED CLIPPING! ****
  562. if (sW < (pimSrc->m_sWidth - sSrcX) )
  563. {
  564. for (sY = sSrcY; sY < sSrcY + sH; sY++,pDstLine += lDstP)
  565. { // Clip off left side:
  566. pSrc = pInfo->m_pBufArry[sY];
  567. pDst = pDstLine;
  568. pCB = pInfo->m_pCodeArry[sY];
  569. sClipWidth = sW; //sSrcX; // initial source...
  570. short sLeftClip = sSrcX;
  571. NextSkip2S:
  572. //==============================================================
  573. // 1) Skip a clear run?
  574. ucCode = *(pCB++); // Get skip length
  575. if (ucCode == 255) continue; // End of line code
  576. // Don't update pDst until you are done skipping!
  577. if ((sLeftClip -= ucCode) < 0)
  578. {
  579. pDst -= sLeftClip; // NOW advance pDst the remainder of the skip
  580. sClipWidth += sLeftClip; // and REDUCE what's left by remainder of skip!
  581. if (sClipWidth <= 0) // done line already?
  582. {
  583. // must jump past rest of code line
  584. do {
  585. ucCode = *(pCB++); // opaque run
  586. ucCode = *(pCB++); // clear run
  587. } while (ucCode != 255);
  588. continue; // start next line!
  589. }
  590. goto NormalOpaque2S;// We're done being clipped
  591. }
  592. //==============================================================
  593. // 2) Skip an opaque run?
  594. ucCode = *(pCB++); // Get skip length
  595. if (ucCode < sLeftClip)
  596. {
  597. sLeftClip -= ucCode; // Adance both pointers, but don't copy!
  598. pSrc += ucCode; // Always need to advance source in an opaque run
  599. //pDst += ucCode; // don't move the pDst until done clipping...
  600. }
  601. else // We've broken out of the Clipped region!
  602. { // Do a partial opaque run:
  603. pSrc += sLeftClip; // We DO need to advance the source!
  604. //pDst += sClipWidth; // and the Dest for the clipped part!
  605. ucCode -= sLeftClip; // Remaining part of run is opaque
  606. if (ucCode > sClipWidth) // a Contracted Run
  607. {
  608. ucCode = (UCHAR)sClipWidth;
  609. sClipWidth = 0;
  610. }
  611. else sClipWidth -= ucCode; // a full opaque run
  612. if (ucCode) // Do an opaque run
  613. {
  614. do *(pDst++) = *(pSrc++); // Copy pixel
  615. while (--ucCode);
  616. }
  617. if (sClipWidth) goto NormalClear2S;
  618. else continue; // next code line!
  619. }
  620. goto NextSkip2S; // Still in the clip region
  621. NormalClear2S:
  622. //==============================================================
  623. // 1) Do a clear run?
  624. ucCode = *(pCB++); // Get skip length
  625. if (ucCode == 255) continue; // End of line code
  626. if ( (sClipWidth -= ucCode) <= 0) continue; // Initial skip is clipped out!
  627. pDst += ucCode;
  628. //==============================================================
  629. // 2) Do an opaque run?
  630. NormalOpaque2S:
  631. ucCode = *(pCB++); // Get run length
  632. if (ucCode > sClipWidth) // a Contracted Run
  633. {
  634. ucCode = (UCHAR)sClipWidth;
  635. sClipWidth = 0;
  636. }
  637. else sClipWidth -= ucCode; // a full opaque run
  638. if (ucCode) // Do an opaque run
  639. {
  640. do *(pDst++) = *(pSrc++); // Copy pixel
  641. while (--ucCode);
  642. }
  643. if (sClipWidth) goto NormalClear2S;
  644. else continue; // next code line!
  645. // Do next line
  646. }
  647. }
  648. else // This is the Left Clip ONLY case!
  649. {
  650. for (sY = sSrcY; sY < sSrcY + sH; sY++,pDstLine += lDstP)
  651. { // Clip off left side:
  652. pSrc = pInfo->m_pBufArry[sY];
  653. pDst = pDstLine;
  654. pCB = pInfo->m_pCodeArry[sY];
  655. sClipWidth = sSrcX; // initial source...
  656. NextSkip:
  657. //==============================================================
  658. // 1) Skip a clear run?
  659. ucCode = *(pCB++); // Get skip length
  660. if (ucCode == 255) continue; // End of line code
  661. // Don't update pDst until you are done skipping!
  662. // pDst += ucCode;
  663. if ((sClipWidth -= ucCode) < 0)
  664. {
  665. pDst -= sClipWidth; // NOW advance pDst the remainder of the skip
  666. goto NormalOpaque;// We're done being clipped
  667. }
  668. //==============================================================
  669. // 2) Skip an opaque run?
  670. ucCode = *(pCB++); // Get skip length
  671. if (ucCode < sClipWidth)
  672. {
  673. sClipWidth -= ucCode; // Adance both pointers, but don't copy!
  674. pSrc += ucCode; // Always need to advance source in an opaque run
  675. //pDst += ucCode; // don't move the pDst until done clipping...
  676. }
  677. else // We've broken out of the Clipped region!
  678. { // Do a partial opaque run:
  679. pSrc += sClipWidth; // We DO need to advance the source!
  680. //pDst += sClipWidth; // and the Dest for the clipped part!
  681. ucCode -= sClipWidth; // Remaining part of run is opaque
  682. if (!ucCode) goto NormalClear;
  683. do *(pDst++) = *(pSrc++); // Should be an unrolled loop
  684. while (--ucCode);
  685. goto NormalClear; // continue
  686. }
  687. goto NextSkip; // Still in the clip region
  688. NormalClear:
  689. //==============================================================
  690. // 1) Do a clear run?
  691. ucCode = *(pCB++); // Get skip length
  692. if (ucCode == 255) continue; // End of line code
  693. pDst += ucCode;
  694. //==============================================================
  695. // 2) Do an opaque run?
  696. NormalOpaque:
  697. ucCode = *(pCB++); // Get skip length
  698. if (!ucCode) goto NormalClear;
  699. do *(pDst++) = *(pSrc++); // Should be an unrolled loop
  700. while (--ucCode);
  701. goto NormalClear;
  702. // Do next line
  703. }
  704. }
  705. }
  706. else
  707. if (sW < (pimSrc->m_sWidth - sSrcX) )
  708. for (sY = sSrcY; sY < sSrcY + sH; sY++,pDstLine += lDstP)
  709. {
  710. // Clip Off Right Side:
  711. pSrc = pInfo->m_pBufArry[sY];
  712. pDst = pDstLine;
  713. pCB = pInfo->m_pCodeArry[sY];
  714. sClipWidth = sW;
  715. NextCodeRC: // Go until used up sClipWidth
  716. //==============================================================
  717. // 1) Do the clear run:
  718. ucCode = *(pCB++); // Get Initial Skip Length
  719. if (ucCode == 255) continue; // End of line code
  720. if ( (sClipWidth -= ucCode) <= 0) continue; // Initial skip is clipped out!
  721. pDst += ucCode; // Advace destination
  722. //==============================================================
  723. // 2) Do the opaque run:
  724. ucCode = *(pCB++); // Get run length
  725. if (ucCode > sClipWidth) // a Contracted Run
  726. {
  727. ucCode = (UCHAR)sClipWidth;
  728. sClipWidth = 0;
  729. }
  730. else sClipWidth -= ucCode; // a full opaque run
  731. if (ucCode) // Do an opaque run
  732. {
  733. do *(pDst++) = *(pSrc++); // Copy pixel
  734. while (--ucCode);
  735. }
  736. if (sClipWidth) goto NextCodeRC; // any space left?
  737. // Do next line!
  738. }
  739. else // do an unclipped BLiT
  740. {
  741. for (sY = sSrcY; sY < sSrcY + sH; sY++,pDstLine += lDstP)
  742. {
  743. pSrc = pInfo->m_pBufArry[sY];
  744. pDst = pDstLine;
  745. pCB = pInfo->m_pCodeArry[sY];
  746. NextCode:
  747. //==============================================================
  748. // 1) Do the clear run:
  749. ucCode = *(pCB)++; // Get Skip Length
  750. if (ucCode == 255) continue;// End of line code
  751. pDst += ucCode; // Skip
  752. //==============================================================
  753. // 2) Do the opaque run:
  754. ucCode = *(pCB)++; // Get Skip Length
  755. if (!ucCode) goto NextCode;
  756. // Below loop is 15% of our CPU time on OSX,
  757. // but MacOSX ships with a _very_ optimized memcpy()...
  758. // (actually, I bet that's true everywhere vs this shitty loop. --ryan.)
  759. #if 1 //PLATFORM_MACOSX
  760. memcpy(pDst, pSrc, ucCode);
  761. pDst += ucCode;
  762. pSrc += ucCode;
  763. #else
  764. do *(pDst++) = *(pSrc++); // Copy pixel
  765. while (--ucCode);
  766. #endif
  767. goto NextCode;
  768. }
  769. }
  770. //*******************************************************************
  771. // IN RELEASE MODE, GIVE THE USER A CHANCE:
  772. #ifndef _DEBUG
  773. //if (gsScreenLocked || gsBufferLocked) goto BLIT_DONTUNLOCK;
  774. #endif
  775. //********************
  776. // OS_SPECIFIC:
  777. //******************** UNLOCK WHATEVER YOU NEED TO
  778. switch (sNeedToUnlock)
  779. {
  780. case 0: // nothing to unlock!
  781. break;
  782. case BUF_MEMORY:
  783. // rspUnlockBuffer();
  784. break;
  785. case BUF_VRAM:
  786. // rspUnlockScreen();
  787. break;
  788. case BUF_VRAM2:
  789. rspUnlockVideoFlipPage();
  790. break;
  791. default:
  792. TRACE("BLiT: Unlocking error!\n");
  793. }
  794. //BLIT_DONTUNLOCK:
  795. return 0;
  796. }
  797. //------------------------------------------------------------------------