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