TerrainCompressor.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  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. // libOMV does not have a packet type defined for the extended parcel format.
  100. // We just happen to know the extended parcel format code is one more than the usual code.
  101. landPacketType++;
  102. }
  103. return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
  104. }
  105. /// <summary>
  106. /// Creates a LayerData packet for compressed land data given a full
  107. /// simulator heightmap and an array of indices of patches to compress
  108. /// </summary>
  109. /// <param name="terrData">
  110. /// Terrain data that can result in a meter square heightmap.
  111. /// </param>
  112. /// <param name="x">
  113. /// Array of indexes in the grid of patches
  114. /// for this simulator.
  115. /// If creating a packet for multiple patches, there will be entries in
  116. /// both the X and Y arrays for each of the patches.
  117. /// For example if patches 1 and 17 are to be sent,
  118. /// x[] = {1,1} and y[] = {0,1} which specifies the patches at
  119. /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
  120. /// </param>
  121. /// <param name="y">
  122. /// Array of indexes in the grid of patches.
  123. /// </param>
  124. /// <param name="type"></param>
  125. /// <param name="pRegionSizeX"></param>
  126. /// <param name="pRegionSizeY"></param>
  127. /// <returns></returns>
  128. public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
  129. {
  130. LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
  131. TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
  132. {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
  133. byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
  134. BitPack bitpack = new BitPack(data, 0);
  135. bitpack.PackBits(header.Stride, 16);
  136. bitpack.PackBits(header.PatchSize, 8);
  137. bitpack.PackBits(type, 8);
  138. for (int i = 0; i < x.Length; i++)
  139. CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
  140. bitpack.PackBits(END_OF_PATCHES, 8);
  141. layer.LayerData.Data = new byte[bitpack.BytePos + 1];
  142. Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
  143. return layer;
  144. }
  145. // Unused: left for historical reference.
  146. public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
  147. {
  148. TerrainPatch.Header header = PrescanPatch(patchData);
  149. header.QuantWBits = 136;
  150. if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
  151. {
  152. header.PatchIDs = (y & 0xFFFF);
  153. header.PatchIDs += (x << 16);
  154. }
  155. else
  156. {
  157. header.PatchIDs = (y & 0x1F);
  158. header.PatchIDs += (x << 5);
  159. }
  160. // NOTE: No idea what prequant and postquant should be or what they do
  161. int wbits;
  162. int[] patch = CompressPatch(patchData, header, 10, out wbits);
  163. wbits = EncodePatchHeader(output, header, patch, (uint)pRegionSizeX, (uint)pRegionSizeY, wbits);
  164. EncodePatch(output, patch, 0, wbits);
  165. }
  166. /// <summary>
  167. /// Add a patch of terrain to a BitPacker
  168. /// </summary>
  169. /// <param name="output">BitPacker to write the patch to</param>
  170. /// <param name="heightmap">
  171. /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
  172. /// </param>
  173. /// <param name="patchX">
  174. /// X offset of the patch to create.
  175. /// </param>
  176. /// <param name="patchY">
  177. /// Y offset of the patch to create.
  178. /// </param>
  179. /// <param name="pRegionSizeX"></param>
  180. /// <param name="pRegionSizeY"></param>
  181. public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
  182. {
  183. TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
  184. header.QuantWBits = 136;
  185. // If larger than legacy region size, pack patch X and Y info differently.
  186. if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
  187. {
  188. header.PatchIDs = (patchY & 0xFFFF);
  189. header.PatchIDs += (patchX << 16);
  190. }
  191. else
  192. {
  193. header.PatchIDs = (patchY & 0x1F);
  194. header.PatchIDs += (patchX << 5);
  195. }
  196. // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
  197. // LogHeader, patchX, patchY, header.DCOffset, header.Range);
  198. // NOTE: No idea what prequant and postquant should be or what they do
  199. int wbits;
  200. int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
  201. wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
  202. EncodePatch(output, patch, 0, wbits);
  203. }
  204. private static TerrainPatch.Header PrescanPatch(float[] patch)
  205. {
  206. TerrainPatch.Header header = new TerrainPatch.Header();
  207. float zmax = -99999999.0f;
  208. float zmin = 99999999.0f;
  209. for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
  210. {
  211. float val = patch[i];
  212. if (val > zmax) zmax = val;
  213. if (val < zmin) zmin = val;
  214. }
  215. header.DCOffset = zmin;
  216. header.Range = (int) ((zmax - zmin) + 1.0f);
  217. return header;
  218. }
  219. // Scan the height info we're returning and return a patch packet header for this patch.
  220. private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
  221. {
  222. TerrainPatch.Header header = new TerrainPatch.Header();
  223. float zmax = -99999999.0f;
  224. float zmin = 99999999.0f;
  225. for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
  226. {
  227. for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
  228. {
  229. float val = terrData[i, j];
  230. if (val > zmax) zmax = val;
  231. if (val < zmin) zmin = val;
  232. }
  233. }
  234. header.DCOffset = zmin;
  235. header.Range = (int)(zmax - zmin + 1.0f);
  236. return header;
  237. }
  238. public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
  239. {
  240. TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
  241. // Quantized word bits
  242. if (header.QuantWBits == END_OF_PATCHES)
  243. return header;
  244. // DC offset
  245. header.DCOffset = bitpack.UnpackFloat();
  246. // Range
  247. header.Range = bitpack.UnpackBits(16);
  248. // Patch IDs (10 bits)
  249. header.PatchIDs = bitpack.UnpackBits(10);
  250. // Word bits
  251. header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
  252. return header;
  253. }
  254. private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
  255. uint pRegionSizeY, int wbits)
  256. {
  257. /*
  258. int temp;
  259. int wbits = (header.QuantWBits & 0x0f) + 2;
  260. uint maxWbits = (uint)wbits + 5;
  261. uint minWbits = ((uint)wbits >> 1);
  262. int wbitsMaxValue;
  263. */
  264. // goal is to determ minimum number of bits to use so all data fits
  265. /*
  266. wbits = (int)minWbits;
  267. wbitsMaxValue = (1 << wbits);
  268. for (int i = 0; i < patch.Length; i++)
  269. {
  270. temp = patch[i];
  271. if (temp != 0)
  272. {
  273. // Get the absolute value
  274. if (temp < 0) temp *= -1;
  275. no coments..
  276. for (int j = (int)maxWbits; j > (int)minWbits; j--)
  277. {
  278. if ((temp & (1 << j)) != 0)
  279. {
  280. if (j > wbits) wbits = j;
  281. break;
  282. }
  283. }
  284. while (temp > wbitsMaxValue)
  285. {
  286. wbits++;
  287. if (wbits == maxWbits)
  288. goto Done;
  289. wbitsMaxValue = 1 << wbits;
  290. }
  291. }
  292. }
  293. Done:
  294. // wbits += 1;
  295. */
  296. // better check
  297. if (wbits > 17)
  298. wbits = 16;
  299. else if (wbits < 3)
  300. wbits = 3;
  301. header.QuantWBits &= 0xf0;
  302. header.QuantWBits |= (wbits - 2);
  303. output.PackBits(header.QuantWBits, 8);
  304. output.PackFloat(header.DCOffset);
  305. output.PackBits(header.Range, 16);
  306. if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
  307. output.PackBits(header.PatchIDs, 32);
  308. else
  309. output.PackBits(header.PatchIDs, 10);
  310. return wbits;
  311. }
  312. private static void IDCTColumn16(float[] linein, float[] lineout, int column)
  313. {
  314. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  315. {
  316. float total = OO_SQRT2*linein[column];
  317. for (int u = 1; u < Constants.TerrainPatchSize; u++)
  318. {
  319. int usize = u*Constants.TerrainPatchSize;
  320. total += linein[usize + column]*CosineTable16[usize + n];
  321. }
  322. lineout[Constants.TerrainPatchSize*n + column] = total;
  323. }
  324. }
  325. private static void IDCTLine16(float[] linein, float[] lineout, int line)
  326. {
  327. const float oosob = 2.0f/Constants.TerrainPatchSize;
  328. int lineSize = line*Constants.TerrainPatchSize;
  329. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  330. {
  331. float total = OO_SQRT2*linein[lineSize];
  332. for (int u = 1; u < Constants.TerrainPatchSize; u++)
  333. {
  334. total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
  335. }
  336. lineout[lineSize + n] = total*oosob;
  337. }
  338. }
  339. /*
  340. private static void DCTLine16(float[] linein, float[] lineout, int line)
  341. {
  342. float total = 0.0f;
  343. int lineSize = line * Constants.TerrainPatchSize;
  344. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  345. {
  346. total += linein[lineSize + n];
  347. }
  348. lineout[lineSize] = OO_SQRT2 * total;
  349. int uptr = 0;
  350. for (int u = 1; u < Constants.TerrainPatchSize; u++)
  351. {
  352. total = 0.0f;
  353. uptr += Constants.TerrainPatchSize;
  354. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  355. {
  356. total += linein[lineSize + n] * CosineTable16[uptr + n];
  357. }
  358. lineout[lineSize + u] = total;
  359. }
  360. }
  361. */
  362. private static void DCTLine16(float[] linein, float[] lineout, int line)
  363. {
  364. // outputs transpose data (lines exchanged with coluns )
  365. // so to save a bit of cpu when doing coluns
  366. float total = 0.0f;
  367. int lineSize = line*Constants.TerrainPatchSize;
  368. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  369. {
  370. total += linein[lineSize + n];
  371. }
  372. lineout[line] = OO_SQRT2*total;
  373. for (int u = Constants.TerrainPatchSize;
  374. u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
  375. u += Constants.TerrainPatchSize)
  376. {
  377. total = 0.0f;
  378. for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
  379. {
  380. total += linein[ptrn]*CosineTable16[ptru];
  381. }
  382. lineout[line + u] = total;
  383. }
  384. }
  385. /*
  386. private static void DCTColumn16(float[] linein, int[] lineout, int column)
  387. {
  388. float total = 0.0f;
  389. // const float oosob = 2.0f / Constants.TerrainPatchSize;
  390. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  391. {
  392. total += linein[Constants.TerrainPatchSize * n + column];
  393. }
  394. // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
  395. lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
  396. for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
  397. {
  398. total = 0.0f;
  399. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  400. {
  401. total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
  402. }
  403. // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
  404. lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
  405. }
  406. }
  407. */
  408. private static void DCTColumn16(float[] linein, int[] lineout, int column)
  409. {
  410. // input columns are in fact stored in lines now
  411. float total = 0.0f;
  412. // const float oosob = 2.0f / Constants.TerrainPatchSize;
  413. int inlinesptr = Constants.TerrainPatchSize*column;
  414. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  415. {
  416. total += linein[inlinesptr + n];
  417. }
  418. // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
  419. lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
  420. for (int uptr = Constants.TerrainPatchSize;
  421. uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
  422. uptr += Constants.TerrainPatchSize)
  423. {
  424. total = 0.0f;
  425. for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
  426. {
  427. total += linein[n]*CosineTable16[ptru];
  428. }
  429. // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
  430. lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
  431. }
  432. }
  433. private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
  434. {
  435. // input columns are in fact stored in lines now
  436. bool dowbits = wbits != maxwbits;
  437. int wbitsMaxValue = 1 << wbits;
  438. float total = 0.0f;
  439. // const float oosob = 2.0f / Constants.TerrainPatchSize;
  440. int inlinesptr = Constants.TerrainPatchSize*column;
  441. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  442. {
  443. total += linein[inlinesptr + n];
  444. }
  445. // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
  446. int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
  447. lineout[CopyMatrix16[column]] = tmp;
  448. if (dowbits)
  449. {
  450. if (tmp < 0) tmp *= -1;
  451. while (tmp > wbitsMaxValue)
  452. {
  453. wbits++;
  454. wbitsMaxValue = 1 << wbits;
  455. if (wbits == maxwbits)
  456. {
  457. dowbits = false;
  458. break;
  459. }
  460. }
  461. }
  462. for (int uptr = Constants.TerrainPatchSize;
  463. uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
  464. uptr += Constants.TerrainPatchSize)
  465. {
  466. total = 0.0f;
  467. for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
  468. {
  469. total += linein[n]*CosineTable16[ptru];
  470. }
  471. tmp = (int) (total*QuantizeTable16[uptr + column]);
  472. lineout[CopyMatrix16[uptr + column]] = tmp;
  473. if (dowbits)
  474. {
  475. if (tmp < 0) tmp *= -1;
  476. while (tmp > wbitsMaxValue)
  477. {
  478. wbits++;
  479. wbitsMaxValue = 1 << wbits;
  480. if (wbits == maxwbits)
  481. {
  482. dowbits = false;
  483. break;
  484. }
  485. }
  486. }
  487. }
  488. return wbits;
  489. }
  490. public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
  491. {
  492. for (int n = 0; n < size*size; n++)
  493. {
  494. // ?
  495. int temp = bitpack.UnpackBits(1);
  496. if (temp != 0)
  497. {
  498. // Value or EOB
  499. temp = bitpack.UnpackBits(1);
  500. if (temp != 0)
  501. {
  502. // Value
  503. temp = bitpack.UnpackBits(1);
  504. if (temp != 0)
  505. {
  506. // Negative
  507. temp = bitpack.UnpackBits((int) header.WordBits);
  508. patches[n] = temp*-1;
  509. }
  510. else
  511. {
  512. // Positive
  513. temp = bitpack.UnpackBits((int) header.WordBits);
  514. patches[n] = temp;
  515. }
  516. }
  517. else
  518. {
  519. // Set the rest to zero
  520. // TODO: This might not be necessary
  521. for (int o = n; o < size*size; o++)
  522. {
  523. patches[o] = 0;
  524. }
  525. break;
  526. }
  527. }
  528. else
  529. {
  530. patches[n] = 0;
  531. }
  532. }
  533. }
  534. private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
  535. {
  536. int maxwbitssize = (1 << wbits) - 1;
  537. if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
  538. {
  539. Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
  540. return;
  541. }
  542. if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
  543. for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
  544. {
  545. int temp = patch[i];
  546. if (temp == 0)
  547. {
  548. bool eob = true;
  549. for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
  550. {
  551. if (patch[j] != 0)
  552. {
  553. eob = false;
  554. break;
  555. }
  556. }
  557. if (eob)
  558. {
  559. output.PackBits(ZERO_EOB, 2);
  560. return;
  561. }
  562. output.PackBits(ZERO_CODE, 1);
  563. }
  564. else
  565. {
  566. if (temp < 0)
  567. {
  568. temp *= -1;
  569. if (temp > maxwbitssize) temp = maxwbitssize;
  570. output.PackBits(NEGATIVE_VALUE, 3);
  571. output.PackBits(temp, wbits);
  572. }
  573. else
  574. {
  575. if (temp > maxwbitssize) temp = maxwbitssize;
  576. output.PackBits(POSITIVE_VALUE, 3);
  577. output.PackBits(temp, wbits);
  578. }
  579. }
  580. }
  581. }
  582. public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
  583. {
  584. float[] block = new float[group.PatchSize*group.PatchSize];
  585. float[] output = new float[group.PatchSize*group.PatchSize];
  586. int prequant = (header.QuantWBits >> 4) + 2;
  587. int quantize = 1 << prequant;
  588. float ooq = 1.0f/quantize;
  589. float mult = ooq*header.Range;
  590. float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
  591. if (group.PatchSize == Constants.TerrainPatchSize)
  592. {
  593. for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
  594. {
  595. block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
  596. }
  597. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  598. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  599. IDCTColumn16(block, ftemp, o);
  600. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  601. IDCTLine16(ftemp, block, o);
  602. }
  603. else
  604. {
  605. for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
  606. {
  607. block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
  608. }
  609. Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
  610. }
  611. for (int j = 0; j < block.Length; j++)
  612. {
  613. output[j] = block[j]*mult + addval;
  614. }
  615. return output;
  616. }
  617. private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
  618. {
  619. float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  620. int wordsize = (prequant - 2) & 0x0f;
  621. float oozrange = 1.0f/header.Range;
  622. float range = (1 << prequant);
  623. float premult = oozrange*range;
  624. float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
  625. header.QuantWBits = wordsize;
  626. header.QuantWBits |= wordsize << 4;
  627. int k = 0;
  628. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  629. {
  630. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  631. block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
  632. }
  633. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  634. int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  635. int maxWbits = prequant + 5;
  636. wbits = (prequant >> 1);
  637. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  638. DCTLine16(block, ftemp, o);
  639. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  640. wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
  641. return itemp;
  642. }
  643. private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
  644. {
  645. float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  646. float oozrange = 1.0f/header.Range;
  647. float range = (1 << prequant);
  648. float premult = oozrange*range;
  649. float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
  650. int wordsize = (prequant - 2) & 0x0f;
  651. header.QuantWBits = wordsize;
  652. header.QuantWBits |= wordsize << 4;
  653. int k = 0;
  654. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  655. {
  656. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  657. block[k++] = patchData[j, i]*premult - sub;
  658. }
  659. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  660. int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  661. int maxWbits = prequant + 5;
  662. wbits = (prequant >> 1);
  663. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  664. DCTLine16(block, ftemp, o);
  665. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  666. wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
  667. return itemp;
  668. }
  669. private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
  670. int prequant, out int wbits)
  671. {
  672. float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  673. int wordsize = prequant;
  674. float oozrange = 1.0f/header.Range;
  675. float range = (1 << prequant);
  676. float premult = oozrange*range;
  677. float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
  678. header.QuantWBits = wordsize - 2;
  679. header.QuantWBits |= (prequant - 2) << 4;
  680. int k = 0;
  681. int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
  682. (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
  683. yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
  684. int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
  685. (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
  686. xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
  687. for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
  688. {
  689. for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
  690. {
  691. block[k++] = terrData[xx, yy] * premult - sub;
  692. }
  693. }
  694. float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  695. int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
  696. int maxWbits = prequant + 5;
  697. wbits = (prequant >> 1);
  698. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  699. DCTLine16(block, ftemp, o);
  700. for (int o = 0; o < Constants.TerrainPatchSize; o++)
  701. wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
  702. return itemp;
  703. }
  704. #region Initialization
  705. private static void BuildDequantizeTable16()
  706. {
  707. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  708. {
  709. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  710. {
  711. DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
  712. }
  713. }
  714. }
  715. private static void BuildQuantizeTable16()
  716. {
  717. const float oosob = 2.0f/Constants.TerrainPatchSize;
  718. for (int j = 0; j < Constants.TerrainPatchSize; j++)
  719. {
  720. for (int i = 0; i < Constants.TerrainPatchSize; i++)
  721. {
  722. // QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
  723. QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
  724. }
  725. }
  726. }
  727. private static void SetupCosines16()
  728. {
  729. const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
  730. for (int u = 0; u < Constants.TerrainPatchSize; u++)
  731. {
  732. for (int n = 0; n < Constants.TerrainPatchSize; n++)
  733. {
  734. CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
  735. }
  736. }
  737. }
  738. private static void BuildCopyMatrix16()
  739. {
  740. bool diag = false;
  741. bool right = true;
  742. int i = 0;
  743. int j = 0;
  744. int count = 0;
  745. while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
  746. {
  747. CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
  748. if (!diag)
  749. {
  750. if (right)
  751. {
  752. if (i < Constants.TerrainPatchSize - 1) i++;
  753. else j++;
  754. right = false;
  755. diag = true;
  756. }
  757. else
  758. {
  759. if (j < Constants.TerrainPatchSize - 1) j++;
  760. else i++;
  761. right = true;
  762. diag = true;
  763. }
  764. }
  765. else
  766. {
  767. if (right)
  768. {
  769. i++;
  770. j--;
  771. if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
  772. }
  773. else
  774. {
  775. i--;
  776. j++;
  777. if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
  778. }
  779. }
  780. }
  781. }
  782. #endregion Initialization
  783. }
  784. }