MultiGrid.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  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. // MULTIGRID.CPP
  21. //
  22. // Created on 03/23/97 JRD
  23. // Implemented 03/23/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/24/97 MJR Switched to rspStricmp() for mac compatibility.
  30. // Also changed a few constants to longs instead
  31. // of ints so that MIN() would work (real strict
  32. // on mac).
  33. //
  34. //////////////////////////////////////////////////////////////////////
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include "System.h"
  38. #ifdef PATHS_IN_INCLUDES
  39. #include "ORANGE/MultiGrid/MultiGrid.h"
  40. #include "ORANGE/str/str.h"
  41. #else
  42. #include "MULTIGRID.H"
  43. #include "str.h"
  44. #endif //PATHS_IN_INCLUDES
  45. //////////////////////////////////////////////////////////////////////
  46. //
  47. // CURRENT CONSTRAINTS (03/23/97)
  48. //
  49. // - Only one level of grid hierarchy
  50. // - Supports only 15-bit data
  51. // - Coarse Grid scale must be in powers of two from (2 - 16384)
  52. //
  53. // BACKWARDS COMPATIBILITY (03/23/97)
  54. //
  55. // - Supports loading RAttribute Files up to version 4
  56. //
  57. // PLANNED ENHANCEMENTS
  58. //
  59. // - Template support for data of any type
  60. // - Multiple hierarchical levels
  61. // - Disjoint grids (hierarchy only where detail is needed)
  62. //
  63. //////////////////////////////////////////////////////////////////////
  64. //////////////////////////////////////////////////////////////////////
  65. //
  66. // RMultiGrid class
  67. //
  68. // This class provides efficient, high speed compression of a 2d data
  69. // field in a way that is transparent to the user. It supports load,
  70. // save, compress, and decompress within the class to facilitate
  71. // utilities.
  72. //
  73. // It compresses by breaking a 2d data field into a coarse grid, and
  74. // attempts to compress the data by 1) replicating tiles wherever
  75. // possible, and 2) describing blocks which are all one value by a
  76. // single value, like a 2d run length encoding.
  77. //
  78. //////////////////////////////////////////////////////////////////////
  79. //////////////////////////////////////////////////////////////////////
  80. // Static Members:
  81. //////////////////////////////////////////////////////////////////////
  82. short RMultiGrid::ms_sShiftToMask[16] =
  83. {0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383};
  84. //////////////////////////////////////////////////////////////////////
  85. // Internal Support Methods:
  86. //////////////////////////////////////////////////////////////////////
  87. //////////////////////////////////////////////////////////////////////
  88. // User Methods:
  89. //////////////////////////////////////////////////////////////////////
  90. // For Debugging
  91. void RMultiGrid::Dump(RImage* pimDst,short sSrcX,short sSrcY,short sDstX,short sDstY,
  92. short sW,short sH)
  93. {
  94. short i,j;
  95. ASSERT(pimDst);
  96. ASSERT(m_psGrid);
  97. ASSERT(!m_sIsCompressed);
  98. for (j=0;j < sH; j++)
  99. for (i=0;i< sW;i++)
  100. {
  101. short sValue = m_psGrid[i + sSrcX + (j + sSrcY)*long(m_sWidth)];
  102. *(pimDst->m_pData + 2*(i + sDstX) + (j + sDstY)*pimDst->m_lPitch) = USHORT(sValue)>>8;
  103. *(pimDst->m_pData + 2*(i + sDstX) + (j + sDstY)*pimDst->m_lPitch+1) = sValue&0xff;
  104. }
  105. }
  106. // For Debugging
  107. void RMultiGrid::DumpGrid(RImage* pimDst)
  108. {
  109. short i,j;
  110. ASSERT(pimDst);
  111. ASSERT(m_psGrid);
  112. ASSERT(m_sIsCompressed);
  113. short sGridW;
  114. short sGridH;
  115. GetGridDimensions(&sGridW,&sGridH);
  116. for (j=0; j < sGridH; j++)
  117. for (i=0; i < sGridW; i++)
  118. {
  119. short sValue = *(m_ppsGridLines[j * (m_sMaskY + 1)] + i);
  120. *(pimDst->m_pData + 2*(i) + (j)*pimDst->m_lPitch) = USHORT(sValue)>>8;
  121. *(pimDst->m_pData + 2*(i) + (j)*pimDst->m_lPitch+1) = sValue&0xff;
  122. }
  123. }
  124. // For Debugging:
  125. void RMultiGrid::DumpData(RImage* pimDst)
  126. {
  127. short i,j;
  128. ASSERT(pimDst);
  129. ASSERT(m_psGrid);
  130. ASSERT(m_sIsCompressed);
  131. for (j=0;j < m_sHeight; j ++)
  132. for (i=0;i< m_sWidth; i++)
  133. {
  134. short sValue = GetVal(i,j);
  135. *(pimDst->m_pData + 2*(i) + (j)*pimDst->m_lPitch) = USHORT(sValue)>>8;
  136. *(pimDst->m_pData + 2*(i) + (j)*pimDst->m_lPitch+1) = sValue&0xff;
  137. }
  138. }
  139. void RMultiGrid::DumpTiles(RImage* pimDst)
  140. {
  141. short sNumTiles = 0 ;// scan for the number of tiles:
  142. short i,j;
  143. short sGridW,sGridH;
  144. GetGridDimensions(&sGridW,&sGridH);
  145. for (j=0;j < sGridH;j++)
  146. {
  147. for (i=0;i < sGridW;i++)
  148. {
  149. short sValue = *(m_ppsGridLines[j * (m_sMaskY + 1)] + i);
  150. if (sValue < 0) sNumTiles = MAX(sNumTiles,short(-sValue));
  151. }
  152. }
  153. TRACE("# of tiles = %hd\n",++sNumTiles);
  154. for (i=0;i < sNumTiles;i++)
  155. {
  156. }
  157. }
  158. //////////////////////////////////////////////////////////////////////
  159. //
  160. // Alloc
  161. //
  162. // Create space for an uncompressed grid:
  163. // Will overwrite old psGrid, so save it first!
  164. //
  165. //////////////////////////////////////////////////////////////////////
  166. short RMultiGrid::Alloc(short sW, short sH)
  167. {
  168. #ifdef _DEBUG
  169. if (m_sIsCompressed)
  170. {
  171. TRACE("RMultiGrid::Alloc: You've already allocated a grid!\n");
  172. return FAILURE;
  173. }
  174. #endif
  175. if (!(m_psGrid = (short*) calloc(sizeof(short),long(sW)*sH) )) return FAILURE;
  176. m_sWidth = sW;
  177. m_sHeight = sH;
  178. return SUCCESS;
  179. }
  180. //////////////////////////////////////////////////////////////////////
  181. //
  182. // AllocGrid
  183. //
  184. // Create space for the compressed grid:
  185. //
  186. //////////////////////////////////////////////////////////////////////
  187. short RMultiGrid::AllocGrid(short sScaleW, short sScaleH)
  188. {
  189. // Set the parameters:
  190. //--------------------------------------------- Convert Input to log 2
  191. short sValue = 16384,sDigit = 14;
  192. short sLogW,sLogH;
  193. short i,j;
  194. while (sScaleW > 0)
  195. {
  196. if (sScaleW >= sValue)
  197. {
  198. #ifdef _DEBUG
  199. if (sValue != sScaleW)
  200. {
  201. TRACE("RMultiGrid::AllocGrid: WARNING - block size not pow2, truncating.\n");
  202. }
  203. #endif
  204. sScaleW = sValue;
  205. sLogW = sDigit;
  206. break;
  207. }
  208. sValue >>= 1;
  209. sDigit--;
  210. }
  211. sValue = 16384,sDigit = 14;
  212. while (sValue > 0)
  213. {
  214. if (sScaleH >= sValue)
  215. {
  216. #ifdef _DEBUG
  217. if (sValue != sScaleH)
  218. {
  219. TRACE("RMultiGrid::AllocGrid: WARNING - block size not pow2, truncating.\n");
  220. }
  221. #endif
  222. sScaleH = sValue;
  223. sLogH = sDigit;
  224. break;
  225. }
  226. sValue >>= 1;
  227. sDigit--;
  228. }
  229. //--------------------------------------------- Set the masks:
  230. m_sShiftX = sLogW;
  231. m_sShiftY = sLogH;
  232. m_sMaskX = sScaleW-1;
  233. m_sMaskY = sScaleH-1;
  234. //--------------------------------------------- Allocate the coarse grid
  235. short sGridW,sGridH;
  236. GetGridDimensions(&sGridW,&sGridH);
  237. short sFullHeight = sGridH * sScaleH;
  238. short* psUncompressed = m_psGrid; // Save old!
  239. //--------------------------------------------- Allocate the Tile Lists:
  240. long lShortTileSize = long(sScaleW) * sScaleH;
  241. long lByteTileSize = lShortTileSize << 1;
  242. long lLongTileSize = lShortTileSize >> 1;
  243. // Initial Max
  244. short sMaxNumTiles = MIN((long)32767, (long)1 + long(sGridW) * (long)sGridH);
  245. if (!(m_psTiles = (short*) calloc(lByteTileSize,sMaxNumTiles ) )) return FAILURE;
  246. //---------------------------------------------Add in the random access:
  247. short *psTile = m_psTiles;
  248. if (!(m_ppsTileList = (short**) calloc(sizeof(short*),sMaxNumTiles ) )) return FAILURE;
  249. for (i=0; i < sMaxNumTiles; i++,psTile += lShortTileSize) m_ppsTileList[i] = psTile;
  250. short sOff = 0;
  251. if (!(m_psTileLine = (short*) calloc(sizeof(short),sScaleH ) )) return FAILURE;
  252. for (i=0;i < sScaleH;i++,sOff += sScaleW) m_psTileLine[i] = sOff;
  253. //--------------------------------------------- Allocate the coarse grid
  254. if (!(m_psGrid = (short*) calloc(sizeof(short),long(sGridW)*sGridH) )) return FAILURE;
  255. //--------------------------------------------- Add in the random access:
  256. if (!(m_ppsGridLines = (short**) calloc(sizeof(short*),sFullHeight ) )) return FAILURE;
  257. for (i=0; i < sFullHeight; i++) m_ppsGridLines[i] = m_psGrid + (i >> m_sShiftY)*sGridW;
  258. //--------------------------------------------- Populate the coarse grid:
  259. short *psSrc,*psSrcLine = psUncompressed;
  260. long lSrcSkip = long(m_sWidth)*sScaleH;
  261. for (j=0;j < sFullHeight;j += sScaleH,psSrcLine += lSrcSkip)
  262. {
  263. psSrc = psSrcLine;
  264. for (i=0;i < sGridW;i++,psSrc += sScaleW)
  265. {
  266. *(m_ppsGridLines[j] + i) = *psSrc;
  267. }
  268. }
  269. return SUCCESS;
  270. }
  271. //////////////////////////////////////////////////////////////////////
  272. // Performs Multigrid compression on the data in place
  273. // Optionally returns the compression statics:
  274. //
  275. // Returns FAILURE if memory could not be allocated,
  276. // or if compression did not succeed ( > 32k blocks were needed)
  277. //
  278. //////////////////////////////////////////////////////////////////////
  279. short RMultiGrid::Compress(
  280. short sTileW, // Size of tiles to try on this data
  281. short sTileH,
  282. long* plSize, // New Data Size (BYTES)
  283. long* plNumBlocks, // Number of unique tiles needed
  284. short sMatchSame // If false, NO TILE WILL BE REUSED
  285. // which increases the speed of compresion
  286. )
  287. {
  288. ASSERT(sTileW > 0);
  289. ASSERT(sTileH > 0);
  290. #ifdef _DEBUG
  291. if (!m_psGrid)
  292. {
  293. TRACE("RMultiGrid::Compress: Gechyerself a map first, you unbelievably flaming bastard!\n");
  294. return -1;
  295. }
  296. if (m_ppsTileList || m_sIsCompressed)
  297. {
  298. TRACE("RMultiGrid::Compress: Uncompress it first, you unbelievably flaming bastard!\n");
  299. return -1;
  300. }
  301. #endif
  302. short *psUncompressedData = m_psGrid;
  303. if (AllocGrid(sTileW,sTileH) ) // alloc error
  304. {
  305. TRACE("RMultiGrid::Compress: Out of memory!\n");
  306. if (m_psGrid) free(m_psGrid);
  307. m_psGrid = psUncompressedData; // restore old data
  308. ClearCompressed();
  309. return FAILURE;
  310. }
  311. // Now, attempt to compress things into blocks:
  312. // First, do only the integral blocks:
  313. short sBlockX,sBlockY,sFullY,i,j;
  314. short sGridVal,sVal;
  315. short sTileNumber = 1; // cannot use -0 as a valid offset!
  316. short sGridW,sGridH;
  317. GetGridDimensions(&sGridW,&sGridH);
  318. short sWholeGridW = sGridW - 1; // guaranteed to be whole.
  319. short sWholeGridH = sGridH - 1;
  320. short sExtraW = m_sWidth - (sWholeGridW << m_sShiftX);
  321. short sExtraH = m_sHeight - (sWholeGridH << m_sShiftY);
  322. short sMaxTile = MIN((long)32767, (long)1 + long(sGridW) * (long)sGridH);
  323. short sShortSize = (m_sMaskX+1)*(m_sMaskY+1);
  324. short sNumMatches = 0;
  325. short sScanH = m_sMaskY + 1;
  326. for (sFullY = 0,sBlockY = 0; sBlockY < sGridH; sBlockY++,sFullY += m_sMaskY + 1)
  327. {
  328. if (sBlockY == sWholeGridH) sScanH = sExtraH;
  329. short sScanW = m_sMaskX + 1;
  330. for (sBlockX = 0; sBlockX < sGridW; sBlockX ++)
  331. {
  332. if (sBlockX == sWholeGridW) sScanW = sExtraW;
  333. sGridVal = *(m_ppsGridLines[sFullY] + sBlockX);
  334. short* psSrcBlock = psUncompressedData + long(sBlockX) * (m_sMaskX + 1) +
  335. long(sFullY) * m_sWidth;
  336. //*********************************************** ANALIZE BLOCK
  337. short sMatch = 1; // homogeneous block?
  338. // do slow, shameful way for now...
  339. // Need to realloc later!
  340. for (j = 0; j < sScanH; j++)
  341. {
  342. for (i = 0; i < sScanW; i++) // only copy what's needed...
  343. {
  344. // copy into temp block:
  345. sVal = psSrcBlock[i + j * long(m_sWidth)];
  346. *(m_ppsTileList[sTileNumber] + m_psTileLine[ j ] + i) = sVal;
  347. if (sVal != sGridVal) sMatch = 0; // was not homogeneous
  348. }
  349. }
  350. short sFound = 0;
  351. if (!sMatch) // store another unique block
  352. {
  353. // ADD IN SCAN TO SEE IF YOU MATCH ANY EXISTING BLOCKS>
  354. if (sMatchSame)
  355. {
  356. short k;
  357. if ((sBlockX != sWholeGridW) && (sBlockY != sWholeGridH)) // do a quick compare:
  358. {
  359. for (k=0;k < sTileNumber;k++)
  360. {
  361. short sComp = 1;
  362. // compare last tile to current:
  363. for (short l=0;l < sShortSize;l++)
  364. {
  365. if (*(m_ppsTileList[k] + l) != *(m_ppsTileList[sTileNumber] + l))
  366. {
  367. sComp = 0;
  368. break;
  369. }
  370. }
  371. if (sComp) // matched an existing tile!
  372. {
  373. *(m_ppsGridLines[sFullY] + sBlockX) = -k;
  374. sFound = 1;
  375. sNumMatches++;
  376. break;
  377. }
  378. }
  379. }
  380. else // only compare the pixels in question:
  381. {
  382. for (k=0;k < sTileNumber;k++)
  383. {
  384. short sComp = 1;
  385. for (j = 0; j < sScanH; j++)
  386. {
  387. for (i = 0; i < sScanW; i++) // only compare what's needed...
  388. {
  389. if (*(m_ppsTileList[k] + m_psTileLine[ j ] + i) !=
  390. *(m_ppsTileList[sTileNumber] + m_psTileLine[ j ] + i) )
  391. {
  392. sComp = 0;
  393. break;
  394. }
  395. }
  396. }
  397. if (sComp) // matched an existing tile!
  398. {
  399. *(m_ppsGridLines[sFullY] + sBlockX) = -k;
  400. sFound = 1;
  401. sNumMatches++;
  402. break;
  403. }
  404. }
  405. }
  406. }
  407. // NEED a new block!
  408. if (!sFound)
  409. {
  410. *(m_ppsGridLines[sFullY] + sBlockX) = -sTileNumber;
  411. sTileNumber++;
  412. if (sTileNumber == 32767)
  413. {
  414. TRACE("Compression overflow! > 32K tiles needed!\n");
  415. if (m_psGrid) free(m_psGrid);
  416. m_psGrid = psUncompressedData; // restore old data
  417. FreeCompressed();
  418. ClearCompressed();
  419. return FAILURE;
  420. }
  421. }
  422. }
  423. //***********************************************
  424. }
  425. }
  426. // Set to new compressed state:
  427. m_sIsCompressed = TRUE;
  428. free(psUncompressedData); // Lose the uncompressed format
  429. // Reallocate the list of blocks to the known size:
  430. short *psOldBlocks = m_psTiles;
  431. long lLen = sShortSize * sizeof(short) * sTileNumber;
  432. m_psTiles = (short*) malloc(lLen);
  433. memcpy(m_psTiles,psOldBlocks,lLen);
  434. free(psOldBlocks);
  435. // Reset the random access
  436. psOldBlocks = m_psTiles;
  437. for (i=0; i < sTileNumber; i++,psOldBlocks += sShortSize) m_ppsTileList[i] = psOldBlocks;
  438. if (plNumBlocks) *plNumBlocks = --sTileNumber;
  439. if (plSize) *plSize = long(sTileNumber) * (long(sShortSize) * sizeof(short) + sizeof(short*))
  440. + long(sGridH) * (sGridW * sizeof(short) + sizeof(short*) );
  441. return SUCCESS;
  442. }
  443. // try again!
  444. short RMultiGrid::Decompress()
  445. {
  446. #ifdef _DEBUG
  447. if (!m_sIsCompressed)
  448. {
  449. TRACE("RMultiGrid::Decompress: Compress it first, you silly silly man!\n");
  450. return -1;
  451. }
  452. #endif
  453. short *psNewGrid = (short*) calloc(sizeof(short),long(m_sWidth)*m_sHeight);
  454. if (!psNewGrid) return -1; // allocation error
  455. // Draw into the new grid:
  456. short i,j;
  457. for (j=0;j < m_sHeight;j++)
  458. {
  459. for (i=0;i < m_sWidth;i++)
  460. {
  461. psNewGrid[i + long(j)*m_sWidth ] = GetVal(i,j);
  462. }
  463. }
  464. // Restore to uncompressed state:
  465. m_sIsCompressed = 0;
  466. FreeCompressed();
  467. ClearCompressed();
  468. free(m_psGrid);
  469. m_psGrid = psNewGrid; // Install it...
  470. return SUCCESS;
  471. }
  472. //////////////////////////////////////////////////////////////////////
  473. //
  474. // Save
  475. //
  476. // Returns FAILURE or SUCCESS
  477. // Will currently only save a compressed Multigrid
  478. //
  479. //////////////////////////////////////////////////////////////////////
  480. short RMultiGrid::Save(RFile* fp)
  481. {
  482. ASSERT(fp);
  483. if (!m_sIsCompressed)
  484. {
  485. TRACE("MultiGrid::Save: Cannot currently save uncompressed MultiGrids. Sorry.\n");
  486. return FAILURE;
  487. }
  488. fp->Write(MULTIGRID_COOKIE);
  489. fp->Write(short(MULTIGRID_CURRENT_VERSION));
  490. fp->Write(m_sWidth);
  491. fp->Write(m_sHeight);
  492. fp->Write(m_sIsCompressed); // ASSUME IT IS COMPRESSED!
  493. fp->Write(m_sMaskX);
  494. fp->Write(m_sMaskY);
  495. fp->Write(short(sizeof(short))); // For future expansion!
  496. short sGridW,sGridH;
  497. GetGridDimensions(&sGridW,&sGridH);
  498. fp->Write(sGridW);
  499. fp->Write(sGridH);
  500. short sNumTiles = GetNumTiles();
  501. fp->Write(sNumTiles);
  502. fp->Write(long(0)); // Reserved1
  503. fp->Write(long(0)); // Reserved2
  504. fp->Write(long(0)); // Reserved3
  505. fp->Write(long(0)); // Reserved4
  506. // Write out the grid of shorts:
  507. short i,j;
  508. for (j=0;j < sGridH; j++)
  509. for (i=0;i<sGridW;i++)
  510. fp->Write(*(m_ppsGridLines[j<<m_sShiftY] + i));
  511. // Write out the tiles, omitting the zeroth black tile.
  512. short sTileLen = (m_sMaskX + 1) * (m_sMaskY + 1);
  513. for (i=1;i < sNumTiles;i++)
  514. {
  515. fp->Write(m_ppsTileList[i],sTileLen);
  516. }
  517. return SUCCESS;
  518. }
  519. //////////////////////////////////////////////////////////////////////
  520. //
  521. // Load
  522. //
  523. // Returns FAILURE or SUCCESS
  524. // Will currently only load a compressed Multigrid, version I
  525. //
  526. //////////////////////////////////////////////////////////////////////
  527. short RMultiGrid::Load(RFile* fp)
  528. {
  529. ASSERT(fp);
  530. if (m_psGrid)
  531. {
  532. TRACE("MultiGrid::Load: Cannot load on top of an existing grid!\n");
  533. return FAILURE;
  534. }
  535. short sVal;
  536. char string[20];
  537. fp->Read(&string[0]);
  538. if (rspStricmp(string,MULTIGRID_COOKIE))
  539. {
  540. TRACE("MultiGrid::Load: Not a MultiGrid File!\n");
  541. return FAILURE;
  542. }
  543. fp->Read(&sVal);
  544. if (sVal != MULTIGRID_CURRENT_VERSION)
  545. {
  546. TRACE("MultiGrid::Load: I don't support this version (%hd).\n",sVal);
  547. return FAILURE;
  548. }
  549. // Let's JAM!
  550. fp->Read(&m_sWidth);
  551. fp->Read(&m_sHeight);
  552. fp->Read(&m_sIsCompressed); // should be compressed
  553. fp->Read(&m_sMaskX);
  554. fp->Read(&m_sMaskY);
  555. short sCodeSize;
  556. fp->Read(&sCodeSize); // normally 2 for short.
  557. short sGridW,sGridH;
  558. fp->Read(&sGridW);
  559. fp->Read(&sGridH);
  560. // ALLOCATE IT
  561. m_psGrid = (short*) calloc(sCodeSize,long(sGridW)*sGridH);
  562. if (!m_psGrid)
  563. {
  564. TRACE("MultiGrid::Load: Out of Memory!!!!\n");
  565. return FAILURE;
  566. }
  567. short sNumTiles;
  568. fp->Read(&sNumTiles);
  569. short sTileLen = (m_sMaskX + 1) * (m_sMaskY + 1);
  570. // Allocate the tiles:
  571. // This appears as a memory leak!
  572. if (!(m_psTiles = (short*)calloc(sTileLen * sCodeSize,sNumTiles)))
  573. {
  574. free(m_psGrid);
  575. TRACE("MultiGrid::Load: Out of Memory!!!!\n");
  576. return FAILURE;
  577. }
  578. long lVal;
  579. fp->Read(&lVal); // Reserved1
  580. fp->Read(&lVal); // Reserved2
  581. fp->Read(&lVal); // Reserved3
  582. fp->Read(&lVal); // Reserved4
  583. short i,j;
  584. // Must generate the shift members to use them now!
  585. m_sShiftX = MaskToShift(m_sMaskX);
  586. m_sShiftY = MaskToShift(m_sMaskY);
  587. // Set up random access for grid:
  588. short sFullHeight = sGridH * (m_sMaskY + 1);
  589. if (!(m_ppsGridLines = (short**) calloc(sizeof(short*),sFullHeight ) )) return FAILURE;
  590. for (i=0; i < sFullHeight; i++) m_ppsGridLines[i] = m_psGrid + (i >> m_sShiftY)*sGridW;
  591. // Read in the grid of shorts:
  592. for (j=0;j < sGridH; j++)
  593. for (i=0;i<sGridW;i++)
  594. fp->Read((m_ppsGridLines[j<<m_sShiftY] + i));
  595. // Set up random access for tiles:
  596. short *psTile = m_psTiles;
  597. if (!(m_ppsTileList = (short**) calloc(sizeof(short*),sNumTiles ) )) return FAILURE;
  598. for (i=0; i < sNumTiles; i++,psTile += sTileLen) m_ppsTileList[i] = psTile;
  599. // Read in the tiles, omitting the zeroth black tile.
  600. for (i=1;i < sNumTiles;i++)
  601. {
  602. fp->Read(m_ppsTileList[i],sTileLen);
  603. }
  604. // Finish up thae random access:
  605. short sOff = 0;
  606. if (!(m_psTileLine = (short*) calloc(sCodeSize,m_sMaskY+1 ) )) return FAILURE;
  607. for (i=0;i < m_sMaskY+1;i++,sOff += m_sMaskX + 1) m_psTileLine[i] = sOff;
  608. // Set the shift values:
  609. return SUCCESS;
  610. }