TerrainCompressor.cs 36 KB

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