TerrainCompressor.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /* Freely adapted from the Aurora version of the terrain compressor.
  28. * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
  29. */
  30. using System;
  31. using System.Reflection;
  32. using log4net;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.Framework;
  35. using OpenSim.Region.Framework.Scenes;
  36. using OpenMetaverse;
  37. using OpenMetaverse.Packets;
  38. namespace OpenSim.Region.ClientStack.LindenUDP
  39. {
  40. public static class OpenSimTerrainCompressor
  41. {
  42. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. private static string LogHeader = "[TERRAIN COMPRESSOR]";
  44. public const int END_OF_PATCHES = 97;
  45. private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
  46. private const int STRIDE = 264;
  47. private const int ZERO_CODE = 0x0;
  48. private const int ZERO_EOB = 0x2;
  49. private const int POSITIVE_VALUE = 0x6;
  50. private const int NEGATIVE_VALUE = 0x7;
  51. private static readonly float[] DequantizeTable16 =
  52. new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  53. private static readonly float[] DequantizeTable32 =
  54. new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  55. private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  56. //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
  57. private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  58. private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  59. private static readonly float[] QuantizeTable16 =
  60. new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  61. static OpenSimTerrainCompressor()
  62. {
  63. // Initialize the decompression tables
  64. BuildDequantizeTable16();
  65. SetupCosines16();
  66. BuildCopyMatrix16();
  67. BuildQuantizeTable16();
  68. }
  69. // Unused: left for historical reference.
  70. public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
  71. int pRegionSizeY)
  72. {
  73. LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
  74. TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
  75. {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
  76. // Should be enough to fit even the most poorly packed data
  77. byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
  78. BitPack bitpack = new BitPack(data, 0);
  79. bitpack.PackBits(header.Stride, 16);
  80. bitpack.PackBits(header.PatchSize, 8);
  81. bitpack.PackBits(type, 8);
  82. foreach (TerrainPatch t in patches)
  83. CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
  84. bitpack.PackBits(END_OF_PATCHES, 8);
  85. layer.LayerData.Data = new byte[bitpack.BytePos + 1];
  86. Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
  87. return layer;
  88. }
  89. // Create a land packet for a single patch.
  90. public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
  91. {
  92. int[] xPieces = new int[1];
  93. int[] yPieces = new int[1];
  94. xPieces[0] = patchX; // patch X dimension
  95. yPieces[0] = patchY;
  96. byte landPacketType = (byte)TerrainPatch.LayerType.Land;
  97. if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
  98. {
  99. landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
  100. }
  101. return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
  102. }
  103. /// <summary>
  104. /// Creates a LayerData packet for compressed land data given a full
  105. /// simulator heightmap and an array of indices of patches to compress
  106. /// </summary>
  107. /// <param name="terrData">
  108. /// Terrain data that can result in a meter square heightmap.
  109. /// </param>
  110. /// <param name="x">
  111. /// Array of indexes in the grid of patches
  112. /// for this simulator.
  113. /// If creating a packet for multiple patches, there will be entries in
  114. /// both the X and Y arrays for each of the patches.
  115. /// For example if patches 1 and 17 are to be sent,
  116. /// x[] = {1,1} and y[] = {0,1} which specifies the patches at
  117. /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
  118. /// </param>
  119. /// <param name="y">
  120. /// Array of indexes in the grid of patches.
  121. /// </param>
  122. /// <param name="type"></param>
  123. /// <param name="pRegionSizeX"></param>
  124. /// <param name="pRegionSizeY"></param>
  125. /// <returns></returns>
  126. public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
  127. {
  128. LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
  129. TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
  130. {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
  131. byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
  132. BitPack bitpack = new BitPack(data, 0);
  133. bitpack.PackBits(header.Stride, 16);
  134. bitpack.PackBits(header.PatchSize, 8);
  135. bitpack.PackBits(type, 8);
  136. for (int i = 0; i < x.Length; i++)
  137. CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
  138. bitpack.PackBits(END_OF_PATCHES, 8);
  139. layer.LayerData.Data = new byte[bitpack.BytePos + 1];
  140. Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
  141. return layer;
  142. }
  143. // Unused: left for historical reference.
  144. public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
  145. {
  146. TerrainPatch.Header header = PrescanPatch(patchData);
  147. header.QuantWBits = 136;
  148. if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
  149. {
  150. header.PatchIDs = (y & 0xFFFF);
  151. header.PatchIDs += (x << 16);
  152. }
  153. else
  154. {
  155. header.PatchIDs = (y & 0x1F);
  156. header.PatchIDs += (x << 5);
  157. }
  158. // NOTE: No idea what prequant and postquant should be or what they do
  159. int wbits;
  160. int[] patch = CompressPatch(patchData, header, 10, out wbits);
  161. wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
  162. EncodePatch(output, patch, 0, wbits);
  163. }
  164. /// <summary>
  165. /// Add a patch of terrain to a BitPacker
  166. /// </summary>
  167. /// <param name="output">BitPacker to write the patch to</param>
  168. /// <param name="heightmap">
  169. /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
  170. /// </param>
  171. /// <param name="patchX">
  172. /// X offset of the patch to create.
  173. /// </param>
  174. /// <param name="patchY">
  175. /// Y offset of the patch to create.
  176. /// </param>
  177. /// <param name="pRegionSizeX"></param>
  178. /// <param name="pRegionSizeY"></param>
  179. public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
  180. {
  181. TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
  182. header.QuantWBits = 136;
  183. // If larger than legacy region size, pack patch X and Y info differently.
  184. if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
  185. {
  186. header.PatchIDs = (patchY & 0xFFFF);
  187. header.PatchIDs += (patchX << 16);
  188. }
  189. else
  190. {
  191. header.PatchIDs = (patchY & 0x1F);
  192. header.PatchIDs += (patchX << 5);
  193. }
  194. // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
  195. // LogHeader, patchX, patchY, header.DCOffset, header.Range);
  196. // NOTE: No idea what prequant and postquant should be or what they do
  197. int wbits;
  198. int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
  199. wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
  200. EncodePatch(output, patch, 0, wbits);
  201. }
  202. private static TerrainPatch.Header PrescanPatch(float[] patch)
  203. {
  204. TerrainPatch.Header header = new TerrainPatch.Header();
  205. float zmax = -99999999.0f;
  206. float zmin = 99999999.0f;
  207. for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
  208. {
  209. float val = patch[i];
  210. if (val > zmax) zmax = val;
  211. if (val < zmin) zmin = val;
  212. }
  213. header.DCOffset = zmin;
  214. header.Range = (int) ((zmax - zmin) + 1.0f);
  215. return header;
  216. }
  217. // Scan the height info we're returning and return a patch packet header for this patch.
  218. private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
  219. {
  220. TerrainPatch.Header header = new TerrainPatch.Header();
  221. float zmax = -99999999.0f;
  222. float zmin = 99999999.0f;
  223. for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
  224. {
  225. for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
  226. {
  227. float val = terrData[i, j];
  228. if (val > zmax) zmax = val;
  229. if (val < zmin) zmin = val;
  230. }
  231. }
  232. header.DCOffset = zmin;
  233. header.Range = (int)(zmax - zmin + 1.0f);
  234. return header;
  235. }
  236. public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
  237. {
  238. TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
  239. // Quantized word bits
  240. if (header.QuantWBits == END_OF_PATCHES)
  241. return header;
  242. // DC offset
  243. header.DCOffset = bitpack.UnpackFloat();
  244. // Range
  245. header.Range = bitpack.UnpackBits(16);
  246. // Patch IDs (10 bits)
  247. header.PatchIDs = bitpack.UnpackBits(10);
  248. // Word bits
  249. header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
  250. return header;
  251. }
  252. private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
  253. uint pRegionSizeY, int wbits)
  254. {
  255. /*
  256. int temp;
  257. int wbits = (header.QuantWBits & 0x0f) + 2;
  258. uint maxWbits = (uint)wbits + 5;
  259. uint minWbits = ((uint)wbits >> 1);
  260. int wbitsMaxValue;
  261. */
  262. // goal is to determ minimum number of bits to use so all data fits
  263. /*
  264. wbits = (int)minWbits;
  265. wbitsMaxValue = (1 << wbits);
  266. for (int i = 0; i < patch.Length; i++)
  267. {
  268. temp = patch[i];
  269. if (temp != 0)
  270. {
  271. // Get the absolute value
  272. if (temp < 0) temp *= -1;
  273. no coments..
  274. for (int j = (int)maxWbits; j > (int)minWbits; j--)
  275. {
  276. if ((temp & (1 << j)) != 0)
  277. {
  278. if (j > wbits) wbits = j;
  279. break;
  280. }
  281. }
  282. while (temp > wbitsMaxValue)
  283. {
  284. wbits++;
  285. if (wbits == maxWbits)
  286. goto Done;
  287. wbitsMaxValue = 1 << wbits;
  288. }
  289. }
  290. }
  291. Done:
  292. // wbits += 1;
  293. */
  294. // better check
  295. if (wbits > 17)
  296. wbits = 16;
  297. else if (wbits < 3)
  298. wbits = 3;
  299. header.QuantWBits &= 0xf0;
  300. header.QuantWBits |= (wbits - 2);
  301. output.PackBits(header.QuantWBits, 8);
  302. output.PackFloat(header.DCOffset);
  303. output.PackBits(header.Range, 16);
  304. if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
  305. output.PackBits(header.PatchIDs, 32);
  306. else
  307. output.PackBits(header.PatchIDs, 10);
  308. return wbits;
  309. }
  310. private static void IDCTColumn16(float[] linein, float[] lineout, int column)
  311. {
  312. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  313. {
  314. float total = OO_SQRT2*linein[column];
  315. for (int u = 1; u < Constants.TerrainPatchSize; u++)
  316. {
  317. int usize = u*Constants.TerrainPatchSize;
  318. total += linein[usize + column]*CosineTable16[usize + n];
  319. }
  320. lineout[Constants.TerrainPatchSize*n + column] = total;
  321. }
  322. }
  323. private static void IDCTLine16(float[] linein, float[] lineout, int line)
  324. {
  325. const float oosob = 2.0f/Constants.TerrainPatchSize;
  326. int lineSize = line*Constants.TerrainPatchSize;
  327. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  328. {
  329. float total = OO_SQRT2*linein[lineSize];
  330. for (int u = 1; u < Constants.TerrainPatchSize; u++)
  331. {
  332. total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
  333. }
  334. lineout[lineSize + n] = total*oosob;
  335. }
  336. }
  337. /*
  338. private static void DCTLine16(float[] linein, float[] lineout, int line)
  339. {
  340. float total = 0.0f;
  341. int lineSize = line * Constants.TerrainPatchSize;
  342. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  343. {
  344. total += linein[lineSize + n];
  345. }
  346. lineout[lineSize] = OO_SQRT2 * total;
  347. int uptr = 0;
  348. for (int u = 1; u < Constants.TerrainPatchSize; u++)
  349. {
  350. total = 0.0f;
  351. uptr += Constants.TerrainPatchSize;
  352. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  353. {
  354. total += linein[lineSize + n] * CosineTable16[uptr + n];
  355. }
  356. lineout[lineSize + u] = total;
  357. }
  358. }
  359. */
  360. private static void DCTLine16(float[] linein, float[] lineout, int line)
  361. {
  362. // outputs transpose data (lines exchanged with coluns )
  363. // so to save a bit of cpu when doing coluns
  364. float total = 0.0f;
  365. int lineSize = line*Constants.TerrainPatchSize;
  366. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  367. {
  368. total += linein[lineSize + n];
  369. }
  370. lineout[line] = OO_SQRT2*total;
  371. for (int u = Constants.TerrainPatchSize;
  372. u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
  373. u += Constants.TerrainPatchSize)
  374. {
  375. total = 0.0f;
  376. for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
  377. {
  378. total += linein[ptrn]*CosineTable16[ptru];
  379. }
  380. lineout[line + u] = total;
  381. }
  382. }
  383. /*
  384. private static void DCTColumn16(float[] linein, int[] lineout, int column)
  385. {
  386. float total = 0.0f;
  387. // const float oosob = 2.0f / Constants.TerrainPatchSize;
  388. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  389. {
  390. total += linein[Constants.TerrainPatchSize * n + column];
  391. }
  392. // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
  393. lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
  394. for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
  395. {
  396. total = 0.0f;
  397. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  398. {
  399. total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
  400. }
  401. // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
  402. lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
  403. }
  404. }
  405. */
  406. private static void DCTColumn16(float[] linein, int[] lineout, int column)
  407. {
  408. // input columns are in fact stored in lines now
  409. float total = 0.0f;
  410. // const float oosob = 2.0f / Constants.TerrainPatchSize;
  411. int inlinesptr = Constants.TerrainPatchSize*column;
  412. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  413. {
  414. total += linein[inlinesptr + n];
  415. }
  416. // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
  417. lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
  418. for (int uptr = Constants.TerrainPatchSize;
  419. uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
  420. uptr += Constants.TerrainPatchSize)
  421. {
  422. total = 0.0f;
  423. for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
  424. {
  425. total += linein[n]*CosineTable16[ptru];
  426. }
  427. // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
  428. lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
  429. }
  430. }
  431. private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
  432. {
  433. // input columns are in fact stored in lines now
  434. bool dowbits = wbits != maxwbits;
  435. int wbitsMaxValue = 1 << wbits;
  436. float total = 0.0f;
  437. // const float oosob = 2.0f / Constants.TerrainPatchSize;
  438. int inlinesptr = Constants.TerrainPatchSize*column;
  439. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  440. {
  441. total += linein[inlinesptr + n];
  442. }
  443. // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
  444. int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
  445. lineout[CopyMatrix16[column]] = tmp;
  446. if (dowbits)
  447. {
  448. if (tmp < 0) tmp *= -1;
  449. while (tmp > wbitsMaxValue)
  450. {
  451. wbits++;
  452. wbitsMaxValue = 1 << wbits;
  453. if (wbits == maxwbits)
  454. {
  455. dowbits = false;
  456. break;
  457. }
  458. }
  459. }
  460. for (int uptr = Constants.TerrainPatchSize;
  461. uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
  462. uptr += Constants.TerrainPatchSize)
  463. {
  464. total = 0.0f;
  465. for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
  466. {
  467. total += linein[n]*CosineTable16[ptru];
  468. }
  469. tmp = (int) (total*QuantizeTable16[uptr + column]);
  470. lineout[CopyMatrix16[uptr + column]] = tmp;
  471. if (dowbits)
  472. {
  473. if (tmp < 0) tmp *= -1;
  474. while (tmp > wbitsMaxValue)
  475. {
  476. wbits++;
  477. wbitsMaxValue = 1 << wbits;
  478. if (wbits == maxwbits)
  479. {
  480. dowbits = false;
  481. break;
  482. }
  483. }
  484. }
  485. }
  486. return wbits;
  487. }
  488. public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
  489. {
  490. for (int n = 0; n < size*size; n++)
  491. {
  492. // ?
  493. int temp = bitpack.UnpackBits(1);
  494. if (temp != 0)
  495. {
  496. // Value or EOB
  497. temp = bitpack.UnpackBits(1);
  498. if (temp != 0)
  499. {
  500. // Value
  501. temp = bitpack.UnpackBits(1);
  502. if (temp != 0)
  503. {
  504. // Negative
  505. temp = bitpack.UnpackBits((int) header.WordBits);
  506. patches[n] = temp*-1;
  507. }
  508. else
  509. {
  510. // Positive
  511. temp = bitpack.UnpackBits((int) header.WordBits);
  512. patches[n] = temp;
  513. }
  514. }
  515. else
  516. {
  517. // Set the rest to zero
  518. // TODO: This might not be necessary
  519. for (int o = n; o < size*size; o++)
  520. {
  521. patches[o] = 0;
  522. }
  523. break;
  524. }
  525. }
  526. else
  527. {
  528. patches[n] = 0;
  529. }
  530. }
  531. }
  532. private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
  533. {
  534. int maxwbitssize = (1 << wbits) - 1;
  535. if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
  536. {
  537. Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
  538. return;
  539. }
  540. if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
  541. for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
  542. {
  543. int temp = patch[i];
  544. if (temp == 0)
  545. {
  546. bool eob = true;
  547. for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
  548. {
  549. if (patch[j] != 0)
  550. {
  551. eob = false;
  552. break;
  553. }
  554. }
  555. if (eob)
  556. {
  557. output.PackBits(ZERO_EOB, 2);
  558. return;
  559. }
  560. output.PackBits(ZERO_CODE, 1);
  561. }
  562. else
  563. {
  564. if (temp < 0)
  565. {
  566. temp *= -1;
  567. if (temp > maxwbitssize) temp = maxwbitssize;
  568. output.PackBits(NEGATIVE_VALUE, 3);
  569. output.PackBits(temp, wbits);
  570. }
  571. else
  572. {
  573. if (temp > maxwbitssize) temp = maxwbitssize;
  574. output.PackBits(POSITIVE_VALUE, 3);
  575. output.PackBits(temp, wbits);
  576. }
  577. }
  578. }
  579. }
  580. public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
  581. {
  582. float[] block = new float[group.PatchSize*group.PatchSize];
  583. float[] output = new float[group.PatchSize*group.PatchSize];
  584. int prequant = (header.QuantWBits >> 4) + 2;
  585. int quantize = 1 << prequant;
  586. float ooq = 1.0f/quantize;
  587. float mult = ooq*header.Range;
  588. float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
  589. if (group.PatchSize == Constants.TerrainPatchSize)
  590. {
  591. for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
  592. {
  593. block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
  594. }
  595. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  596. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  597. IDCTColumn16(block, ftemp, o);
  598. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  599. IDCTLine16(ftemp, block, o);
  600. }
  601. else
  602. {
  603. for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
  604. {
  605. block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
  606. }
  607. Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
  608. }
  609. for (int j = 0; j < block.Length; j++)
  610. {
  611. output[j] = block[j]*mult + addval;
  612. }
  613. return output;
  614. }
  615. private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
  616. {
  617. float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  618. int wordsize = (prequant - 2) & 0x0f;
  619. float oozrange = 1.0f/header.Range;
  620. float range = (1 << prequant);
  621. float premult = oozrange*range;
  622. float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
  623. header.QuantWBits = wordsize;
  624. header.QuantWBits |= wordsize << 4;
  625. int k = 0;
  626. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  627. {
  628. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  629. block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
  630. }
  631. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  632. int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  633. int maxWbits = prequant + 5;
  634. wbits = (prequant >> 1);
  635. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  636. DCTLine16(block, ftemp, o);
  637. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  638. wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
  639. return itemp;
  640. }
  641. private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
  642. {
  643. float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  644. float oozrange = 1.0f/header.Range;
  645. float range = (1 << prequant);
  646. float premult = oozrange*range;
  647. float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
  648. int wordsize = (prequant - 2) & 0x0f;
  649. header.QuantWBits = wordsize;
  650. header.QuantWBits |= wordsize << 4;
  651. int k = 0;
  652. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  653. {
  654. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  655. block[k++] = patchData[j, i]*premult - sub;
  656. }
  657. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  658. int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  659. int maxWbits = prequant + 5;
  660. wbits = (prequant >> 1);
  661. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  662. DCTLine16(block, ftemp, o);
  663. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  664. wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
  665. return itemp;
  666. }
  667. private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
  668. int prequant, out int wbits)
  669. {
  670. float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  671. int wordsize = prequant;
  672. float oozrange = 1.0f/header.Range;
  673. float range = (1 << prequant);
  674. float premult = oozrange*range;
  675. float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
  676. header.QuantWBits = wordsize - 2;
  677. header.QuantWBits |= (prequant - 2) << 4;
  678. int k = 0;
  679. int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
  680. (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
  681. yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
  682. int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
  683. (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
  684. xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
  685. for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
  686. {
  687. for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
  688. {
  689. block[k++] = terrData[xx, yy] * premult - sub;
  690. }
  691. }
  692. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  693. int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  694. int maxWbits = prequant + 5;
  695. wbits = (prequant >> 1);
  696. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  697. DCTLine16(block, ftemp, o);
  698. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  699. wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
  700. return itemp;
  701. }
  702. #region Initialization
  703. private static void BuildDequantizeTable16()
  704. {
  705. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  706. {
  707. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  708. {
  709. DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
  710. }
  711. }
  712. }
  713. private static void BuildQuantizeTable16()
  714. {
  715. const float oosob = 2.0f/Constants.TerrainPatchSize;
  716. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  717. {
  718. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  719. {
  720. // QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
  721. QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
  722. }
  723. }
  724. }
  725. private static void SetupCosines16()
  726. {
  727. const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
  728. for (int u = 0; u < Constants.TerrainPatchSize; u++)
  729. {
  730. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  731. {
  732. CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
  733. }
  734. }
  735. }
  736. private static void BuildCopyMatrix16()
  737. {
  738. bool diag = false;
  739. bool right = true;
  740. int i = 0;
  741. int j = 0;
  742. int count = 0;
  743. while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
  744. {
  745. CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
  746. if (!diag)
  747. {
  748. if (right)
  749. {
  750. if (i < Constants.TerrainPatchSize - 1) i++;
  751. else j++;
  752. right = false;
  753. diag = true;
  754. }
  755. else
  756. {
  757. if (j < Constants.TerrainPatchSize - 1) j++;
  758. else i++;
  759. right = true;
  760. diag = true;
  761. }
  762. }
  763. else
  764. {
  765. if (right)
  766. {
  767. i++;
  768. j--;
  769. if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
  770. }
  771. else
  772. {
  773. i--;
  774. j++;
  775. if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
  776. }
  777. }
  778. }
  779. }
  780. #endregion Initialization
  781. }
  782. }