clockwerk-opensim – Blame information for rev 1

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