MultiGridIndirect.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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. //
  20. // MULTIGRIDINDIRECT.CPP
  21. //
  22. // Created on 05/01/97 JRD
  23. // Implemented 05/01/97 JRD
  24. //
  25. // 05/08/97 JMI Added #include <string.h> for strcmp*(). I guess
  26. // that, in VC <= 4.1, the strcmp*() protos are not
  27. // in stdlib.h.
  28. //
  29. // 06/28/97 MJR Minor changes to get it working on the mac.
  30. //
  31. //////////////////////////////////////////////////////////////////////
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include "System.h"
  35. #ifdef PATHS_IN_INCLUDES
  36. #include "ORANGE/MultiGrid/MultiGrid.h"
  37. #include "ORANGE/MultiGrid/MultiGridIndirect.h"
  38. #else
  39. #include "MULTIGRID.H"
  40. #include "MULTIGRIDINDIRECT.H"
  41. #endif //PATHS_IN_INCLUDES
  42. //////////////////////////////////////////////////////////////////////
  43. //
  44. // CURRENT CONSTRAINTS (03/23/97)
  45. //
  46. // - Only one level of grid hierarchy
  47. // - Supports only 15-bit data
  48. // - Coarse Grid scale must be in powers of two from (2 - 16384)
  49. // - Supports only 8-bit palette values
  50. // - Supports a maximum of four planes (16 tables)
  51. //
  52. // BACKWARDS COMPATIBILITY (03/23/97)
  53. //
  54. // - will try to still load conventional RMultiGrids
  55. //
  56. // PLANNED ENHANCEMENTS
  57. //
  58. // - Template support for data of any type
  59. // - Multiple hierarchical levels
  60. // - Disjoint grids (hierarchy only where detail is needed)
  61. //
  62. //////////////////////////////////////////////////////////////////////
  63. //////////////////////////////////////////////////////////////////////
  64. //
  65. // RMultiGridIndirect class
  66. //
  67. // This class provides efficient, high speed compression of a 2d data
  68. // field in a way that is transparent to the user. It supports load,
  69. // save, compress, and decompress within the class to facilitate
  70. // utilities.
  71. //
  72. // It compresses by breaking a 2d data field into a coarse grid, and
  73. // attempts to compress the data by 1) replicating tiles wherever
  74. // possible, and 2) describing blocks which are all one value by a
  75. // single value, like a 2d run length encoding.
  76. //
  77. // Then, as further compression compared with MultiGrids, it then
  78. // creates a local palette for each coarse grid, so the values
  79. // within each grid stay small.
  80. //
  81. //////////////////////////////////////////////////////////////////////
  82. //////////////////////////////////////////////////////////////////////
  83. // Produce a valid OR mask to se a plane number
  84. // (ZERO IS A VALID PLANE NUMBER)
  85. short RMultiGridIndirect::ms_asColorToPlane[MGI_MAX_PLANES] =
  86. {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
  87. // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  88. // PLANE NUMBER ^ ^ ^ ^ ^
  89. //////////////////////////////////////////////////////////////////////
  90. // Internal Support Methods:
  91. //////////////////////////////////////////////////////////////////////
  92. //////////////////////////////////////////////////////////////////////
  93. // User Methods:
  94. //////////////////////////////////////////////////////////////////////
  95. // For Debugging
  96. void RMultiGridIndirect::DumpPalette(RImage* pimDst,short sSrcX,short sSrcY,short sDstX,short sDstY,
  97. short sW,short sH)
  98. {
  99. //short i,j;
  100. }
  101. // Low level alloc, JUST of the palette grid.
  102. // Width and height should match that of the RMultiGrid
  103. short RMultiGridIndirect::Alloc(short sW, short sH, short sMaxPlanes,
  104. short sTileW, short sTileH)
  105. {
  106. ASSERT(!m_pucPalette);
  107. ASSERT(!m_ppucAccessY);
  108. ASSERT(!m_plAccessX);
  109. ASSERT(sW > 1);
  110. ASSERT(sH > 1);
  111. ASSERT((sMaxPlanes > 0) && (sMaxPlanes <= MGI_MAX_PLANES));
  112. short sGridW = (sW / sTileW) + 1;
  113. short sGridH = (sH / sTileH) + 1;
  114. m_pucPalette = (UCHAR*) calloc(sMaxPlanes,long(sGridW) * sGridH);
  115. ASSERT(m_pucPalette);
  116. m_plAccessX = (ULONG*) calloc(sizeof(long),sGridW * sTileW);
  117. ASSERT(m_plAccessX);
  118. m_ppucAccessY = (UCHAR**) calloc( sizeof(UCHAR*),long(sGridH)*sTileH );
  119. ASSERT(m_ppucAccessY);
  120. // Populate the pointer list:
  121. UCHAR* pY = m_pucPalette;
  122. long lOffset = long(sGridW)*sMaxPlanes;
  123. short i,j;
  124. for (i=0,j=0;i<sGridH;pY += lOffset,i++)
  125. {
  126. for (short k=0;k < sTileH;k++)
  127. {
  128. m_ppucAccessY[j++] = pY;
  129. }
  130. }
  131. long lX = 0;
  132. for (i=0,j=0;i<sGridW;lX += sMaxPlanes,i++)
  133. {
  134. for (short k=0;k < sTileW;k++)
  135. {
  136. m_plAccessX[j++] = lX;
  137. }
  138. }
  139. m_sWidth = sW;
  140. m_sHeight = sH;
  141. m_sTileW = sTileW;
  142. m_sTileH = sTileH;
  143. m_sGridW = sGridW;
  144. m_sGridH = sGridH;
  145. m_sMaxPlanes = sMaxPlanes;
  146. m_pimTempTile = new RImage;
  147. // Keep pitch equal to width:
  148. m_pimTempTile->CreateImage(m_sTileW,m_sTileH,RImage::BMP8,m_sTileW);
  149. m_lTileLen = long(m_sTileW) * m_sTileH;
  150. return SUCCESS;
  151. }
  152. /////////////////////////////////////////////////////////////////////
  153. // Some of the following functions operate on both RMultiAlphas
  154. // AND the palette grid.
  155. /////////////////////////////////////////////////////////////////////
  156. // This is at the pure app level. How it could be a valid part of
  157. // an orange function is unclear:
  158. //
  159. short RMultiGridIndirect::AddFSPR1(RImage* pimSrc,short sLogX,short sLogY,
  160. UCHAR ucVal,short sMaxW,short sMaxH)
  161. {
  162. ASSERT(pimSrc);
  163. ASSERT(pimSrc->m_type == RImage::FSPR1);
  164. short sRet = SUCCESS;
  165. // Note that the FSPR1 can't clip, so if the buffer size is wrong
  166. // it won't copy over.
  167. if (m_pimBuffer && (sMaxW || sMaxH))
  168. {
  169. if ( (m_pimBuffer->m_sWidth != sMaxW) ||
  170. (m_pimBuffer->m_sHeight != sMaxH))
  171. {
  172. delete m_pimBuffer;
  173. m_pimBuffer = NULL;
  174. }
  175. }
  176. if (!m_pimBuffer)
  177. {
  178. m_pimBuffer = new RImage;
  179. m_pimBuffer->CreateImage(sMaxW,sMaxH,RImage::BMP8);
  180. }
  181. //--------------------------------------------
  182. // 1) clear the buffer
  183. rspRect(UCHAR(0),m_pimBuffer,0,0,m_pimBuffer->m_sWidth,
  184. m_pimBuffer->m_sHeight);
  185. // 2) copy in the region to be tiled
  186. rspBlit(UCHAR(1),pimSrc,m_pimBuffer,0,0);
  187. short sX,sY,sX2,sY2;
  188. // IMPORTANT STEP 2.5! I cannot guarantee that the chosen
  189. // region lies within my overall world, so I must clip it!
  190. // 2.5) Clip the requested region to the real region:
  191. short sClipW = m_pimBuffer->m_sWidth;
  192. short sClipH = m_pimBuffer->m_sHeight;
  193. short sClip;
  194. sClip = -sLogX;
  195. if (sClip > 0) { sLogX += sClip; sClipW -= sClip; }
  196. sClip = -sLogY;
  197. if (sClip > 0) { sLogY += sClip; sClipH -= sClip; }
  198. sClip = sLogX + sClipW - m_sWidth;
  199. if (sClip > 0) { sClipW -= sClip; }
  200. sClip = sLogY + sClipH - m_sHeight;
  201. if (sClip > 0) { sClipH -= sClip; }
  202. if (!sClipW && !sClipH)
  203. {
  204. TRACE("RMultiGridIndirect::AddFSPR1: WARNING: added region clipped out.\n");
  205. return SUCCESS;
  206. }
  207. // 3) calculate the logical tile rects covered by the region:
  208. //*************************************************** Use DIVMODS!
  209. //************************** BETTER YET, USE POWERS OF 2!
  210. sX = sLogX & ~(m_sTileW-1); // look for powers of two!
  211. sY = sLogY & ~(m_sTileH-1);
  212. sX2 = (sLogX + sClipW + m_sTileW - 2) & ~(m_sTileW-1);
  213. sY2 = (sLogY + sClipH + m_sTileH - 2) & ~(m_sTileH-1);
  214. short sTileX,sTileY,sTileW,sTileH;
  215. sTileX = sX / m_sTileW;
  216. sTileY = sY / m_sTileH;
  217. sTileW = (sX2 - sX + 1) / m_sTileW;
  218. sTileH = (sY2 - sY + 1) / m_sTileH;
  219. // Now process each tile individually!
  220. short i,j;
  221. short sCurX,sCurY = sY;
  222. for (j = 0; j < sTileH; j++,sCurY += m_sTileH)
  223. {
  224. sCurX = sX;
  225. for (i = 0;i < sTileW; i++,sCurX += m_sTileW)
  226. {
  227. //===================================================
  228. // Add a tile into the attribute layer!
  229. //===================================================
  230. // 1) Copy the tile square into the general Tile buffer:
  231. CacheTile(m_pimBuffer,sCurX - sLogX,sCurY - sLogY);
  232. // 2) if nontrivial, determine the index color
  233. if (Contains(1))
  234. {
  235. short sIndex = NumPalEntries(sCurX,sCurY);
  236. ASSERT(sIndex < m_sMaxPlanes); // overflow
  237. if (sIndex >= m_sMaxPlanes)
  238. {
  239. TRACE("RMultiGridIndirect::AddFSPR1: "
  240. "Exceeded %hd overlapping regions at (%hd,%hd)\n",
  241. m_sMaxPlanes,sCurX,sCurY);
  242. sRet = FAILURE;
  243. }
  244. else
  245. {
  246. // 3) Insert the palette entry and choose a plane:
  247. SetPalette(sCurX,sCurY,sIndex,ucVal);
  248. short sPlaneVal = ms_asColorToPlane[sIndex];
  249. // 4) Draw the tile into the attribute map:
  250. TileOR(UCHAR(1),USHORT(sPlaneVal),sCurX,sCurY,1);
  251. }
  252. }
  253. //===================================================
  254. }
  255. }
  256. return sRet;
  257. }
  258. void RMultiGridIndirect::TileOR(UCHAR ucKey,USHORT usValueOR,short sDstX,short sDstY,
  259. short sClip) // you can turn off the half clipping:
  260. {
  261. ASSERT(m_pmg);
  262. ASSERT(m_pmg->m_psGrid);
  263. ASSERT(!m_pmg->m_sIsCompressed);
  264. ASSERT(usValueOR < 32768);
  265. //-------------- half clipping ------------
  266. USHORT* pusAttrib = (USHORT*) m_pmg->m_psGrid;
  267. short sW = m_sTileW,sH = m_sTileH;
  268. if (sClip)
  269. {
  270. short sClip;
  271. sClip = m_pmg->m_sWidth - sDstX - m_sTileW;
  272. if (sClip < 0) sW += sClip;
  273. sClip = m_pmg->m_sHeight - sDstY - m_sTileH;
  274. if (sClip < 0) sH += sClip;
  275. if ( (sW < 1) || (sH < 1) ) return; // clipped out
  276. }
  277. long lDstP = m_pmg->m_sWidth; // (in shorts)
  278. long lSrcP = m_sTileW;
  279. UCHAR* pSrc,*pSrcLine = m_pimTempTile->m_pData;
  280. USHORT* pDst,*pDstLine = (USHORT*)m_pmg->m_psGrid;
  281. // Adjust for actual coordinates!!!!
  282. pDstLine += long(m_pmg->m_sWidth) * sDstY + sDstX;
  283. short i,j;
  284. for (j=0;j < sH;j++,pSrcLine += lSrcP,pDstLine += lDstP)
  285. {
  286. pDst = pDstLine;
  287. pSrc = pSrcLine;
  288. for (i=0;i < sW;i++,pSrc++,pDst++)
  289. {
  290. if (*pSrc == ucKey)
  291. *pDst |= usValueOR;
  292. }
  293. }
  294. }
  295. // Load a compressed data set from disk
  296. //
  297. short RMultiGridIndirect::Load(RFile* fp)
  298. {
  299. ASSERT(!m_pmg);
  300. ASSERT(!m_pucPalette);
  301. short sVer;
  302. char type[256];
  303. fp->Read(type);
  304. if (strcmp(type,"__MultiGridIndirect__"))
  305. {
  306. TRACE("RMultiGridIndirect::Load: Not a MGI!\n");
  307. return FAILURE;
  308. }
  309. fp->Read(&sVer);
  310. if (sVer != 1)
  311. {
  312. TRACE("RMultiGridIndirect::Load: Can't load MGI version %hd!\n",
  313. sVer);
  314. return FAILURE;
  315. }
  316. // Assume we have an initialized instance here:
  317. fp->Read(&m_sWidth);
  318. fp->Read(&m_sHeight);
  319. fp->Read(&m_sGridW);
  320. fp->Read(&m_sGridH);
  321. fp->Read(&m_sTileW);
  322. fp->Read(&m_sTileH);
  323. fp->Read(&m_sMaxPlanes);
  324. long lRes = 0;
  325. fp->Read(&lRes);
  326. fp->Read(&lRes);
  327. fp->Read(&lRes);
  328. fp->Read(&lRes);
  329. // just the palette data:
  330. long lLen = long(m_sGridW) * m_sGridH * m_sMaxPlanes;
  331. m_pucPalette = (UCHAR*) calloc(1,lLen);
  332. fp->Read(m_pucPalette,lLen);
  333. // And send out the sttribute map:
  334. m_pmg = new RMultiGrid;
  335. if (m_pmg->Load(fp)!=SUCCESS)
  336. {
  337. TRACE("RMultiGridIndirect::Load: Couldn't Load Multigrid!\n");
  338. return FAILURE;
  339. }
  340. // Need to hook up all the access variables!
  341. m_plAccessX = (ULONG*) calloc(sizeof(long),m_sGridW * m_sTileW);
  342. ASSERT(m_plAccessX);
  343. m_ppucAccessY = (UCHAR**) calloc( sizeof(UCHAR*),long(m_sGridH)*m_sTileH );
  344. ASSERT(m_ppucAccessY);
  345. // Populate the pointer list:
  346. UCHAR* pY = m_pucPalette;
  347. long lOffset = long(m_sGridW)*m_sMaxPlanes;
  348. short i,j;
  349. for (i=0,j=0;i<m_sGridH;pY += lOffset,i++)
  350. {
  351. for (short k=0;k < m_sTileH;k++)
  352. {
  353. m_ppucAccessY[j++] = pY;
  354. }
  355. }
  356. long lX = 0;
  357. for (i=0,j=0;i<m_sGridW;lX += m_sMaxPlanes,i++)
  358. {
  359. for (short k=0;k < m_sTileW;k++)
  360. {
  361. m_plAccessX[j++] = lX;
  362. }
  363. }
  364. m_pimTempTile = new RImage;
  365. // Keep pitch equal to width:
  366. m_pimTempTile->CreateImage(m_sTileW,m_sTileH,RImage::BMP8,m_sTileW);
  367. m_lTileLen = long(m_sTileW) * m_sTileH;
  368. return SUCCESS;
  369. }
  370. //////////////////////////////////////////////////////////////////////
  371. // Save a compressed data set to disk
  372. //
  373. short RMultiGridIndirect::Save(RFile* fp)
  374. {
  375. ASSERT(m_pmg);
  376. ASSERT(m_pmg->m_sIsCompressed);
  377. ASSERT(m_pucPalette);
  378. short sVer = 1;
  379. fp->Write("__MultiGridIndirect__");
  380. fp->Write(sVer);
  381. fp->Write(m_sWidth);
  382. fp->Write(m_sHeight);
  383. fp->Write(m_sGridW);
  384. fp->Write(m_sGridH);
  385. fp->Write(m_sTileW);
  386. fp->Write(m_sTileH);
  387. fp->Write(m_sMaxPlanes);
  388. long lRes = 0;
  389. fp->Write(lRes);
  390. fp->Write(lRes);
  391. fp->Write(lRes);
  392. fp->Write(lRes);
  393. // just the palette data:
  394. long lLen = long(m_sGridW) * m_sGridH * m_sMaxPlanes;
  395. fp->Write(m_pucPalette,lLen);
  396. // And send out the sttribute map:
  397. m_pmg->Save(fp);
  398. return SUCCESS;
  399. }