opensim – Blame information for rev 1

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