corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using OpenMetaverse.Packets;
29  
30 namespace OpenMetaverse
31 {
32 [Serializable]
33 public class TerrainPatch
34 {
35 #region Enums and Structs
36  
37 public enum LayerType : byte
38 {
39 Land = 0x4C, // 'L'
40 LandExtended = 0x4D, // 'M'
41 Water = 0x57, // 'W'
42 WaterExtended = 0x57, // 'X'
43 Wind = 0x37, // '7'
44 WindExtended = 0x39, // '9'
45 Cloud = 0x38, // '8'
46 CloudExtended = 0x3A // ':'
47 }
48  
49 public struct GroupHeader
50 {
51 public int Stride;
52 public int PatchSize;
53 public LayerType Type;
54 }
55  
56 public struct Header
57 {
58 public float DCOffset;
59 public int Range;
60 public int QuantWBits;
61 public int PatchIDs;
62 public uint WordBits;
63  
64 public int X
65 {
66 get { return PatchIDs >> 5; }
67 set { PatchIDs += (value << 5); }
68 }
69  
70 public int Y
71 {
72 get { return PatchIDs & 0x1F; }
73 set { PatchIDs |= value & 0x1F; }
74 }
75 }
76  
77 #endregion Enums and Structs
78  
79 /// <summary>X position of this patch</summary>
80 public int X;
81 /// <summary>Y position of this patch</summary>
82 public int Y;
83 /// <summary>A 16x16 array of floats holding decompressed layer data</summary>
84 public float[] Data;
85 }
86  
87 public static class TerrainCompressor
88 {
89 public const int PATCHES_PER_EDGE = 16;
90 public const int END_OF_PATCHES = 97;
91  
92 private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
93 private const int STRIDE = 264;
94  
95 private const int ZERO_CODE = 0x0;
96 private const int ZERO_EOB = 0x2;
97 private const int POSITIVE_VALUE = 0x6;
98 private const int NEGATIVE_VALUE = 0x7;
99  
100 private static readonly float[] DequantizeTable16 = new float[16 * 16];
101 private static readonly float[] DequantizeTable32 = new float[16 * 16];
102 private static readonly float[] CosineTable16 = new float[16 * 16];
103 //private static readonly float[] CosineTable32 = new float[16 * 16];
104 private static readonly int[] CopyMatrix16 = new int[16 * 16];
105 private static readonly int[] CopyMatrix32 = new int[16 * 16];
106 private static readonly float[] QuantizeTable16 = new float[16 * 16];
107  
108 static TerrainCompressor()
109 {
110 // Initialize the decompression tables
111 BuildDequantizeTable16();
112 SetupCosines16();
113 BuildCopyMatrix16();
114 BuildQuantizeTable16();
115 }
116  
117 public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, TerrainPatch.LayerType type)
118 {
119 LayerDataPacket layer = new LayerDataPacket();
120 layer.LayerID.Type = (byte)type;
121  
122 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader();
123 header.Stride = STRIDE;
124 header.PatchSize = 16;
125 header.Type = type;
126  
127 // Should be enough to fit even the most poorly packed data
128 byte[] data = new byte[patches.Length * 16 * 16 * 2];
129 BitPack bitpack = new BitPack(data, 0);
130 bitpack.PackBits(header.Stride, 16);
131 bitpack.PackBits(header.PatchSize, 8);
132 bitpack.PackBits((int)header.Type, 8);
133  
134 for (int i = 0; i < patches.Length; i++)
135 CreatePatch(bitpack, patches[i].Data, patches[i].X, patches[i].Y);
136  
137 bitpack.PackBits(END_OF_PATCHES, 8);
138  
139 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
140 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
141  
142 return layer;
143 }
144  
145 /// <summary>
146 /// Creates a LayerData packet for compressed land data given a full
147 /// simulator heightmap and an array of indices of patches to compress
148 /// </summary>
149 /// <param name="heightmap">A 256 * 256 array of floating point values
150 /// specifying the height at each meter in the simulator</param>
151 /// <param name="patches">Array of indexes in the 16x16 grid of patches
152 /// for this simulator. For example if 1 and 17 are specified, patches
153 /// x=1,y=0 and x=1,y=1 are sent</param>
154 /// <returns></returns>
155 public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches)
156 {
157 LayerDataPacket layer = new LayerDataPacket();
158 layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land;
159  
160 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader();
161 header.Stride = STRIDE;
162 header.PatchSize = 16;
163 header.Type = TerrainPatch.LayerType.Land;
164  
165 byte[] data = new byte[1536];
166 BitPack bitpack = new BitPack(data, 0);
167 bitpack.PackBits(header.Stride, 16);
168 bitpack.PackBits(header.PatchSize, 8);
169 bitpack.PackBits((int)header.Type, 8);
170  
171 for (int i = 0; i < patches.Length; i++)
172 CreatePatchFromHeightmap(bitpack, heightmap, patches[i] % 16, (patches[i] - (patches[i] % 16)) / 16);
173  
174 bitpack.PackBits(END_OF_PATCHES, 8);
175  
176 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
177 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
178  
179 return layer;
180 }
181  
182 public static LayerDataPacket CreateLandPacket(float[] patchData, int x, int y)
183 {
184 LayerDataPacket layer = new LayerDataPacket();
185 layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land;
186  
187 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader();
188 header.Stride = STRIDE;
189 header.PatchSize = 16;
190 header.Type = TerrainPatch.LayerType.Land;
191  
192 byte[] data = new byte[1536];
193 BitPack bitpack = new BitPack(data, 0);
194 bitpack.PackBits(header.Stride, 16);
195 bitpack.PackBits(header.PatchSize, 8);
196 bitpack.PackBits((int)header.Type, 8);
197  
198 CreatePatch(bitpack, patchData, x, y);
199  
200 bitpack.PackBits(END_OF_PATCHES, 8);
201  
202 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
203 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
204  
205 return layer;
206 }
207  
208 public static LayerDataPacket CreateLandPacket(float[,] patchData, int x, int y)
209 {
210 LayerDataPacket layer = new LayerDataPacket();
211 layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land;
212  
213 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader();
214 header.Stride = STRIDE;
215 header.PatchSize = 16;
216 header.Type = TerrainPatch.LayerType.Land;
217  
218 byte[] data = new byte[1536];
219 BitPack bitpack = new BitPack(data, 0);
220 bitpack.PackBits(header.Stride, 16);
221 bitpack.PackBits(header.PatchSize, 8);
222 bitpack.PackBits((int)header.Type, 8);
223  
224 CreatePatch(bitpack, patchData, x, y);
225  
226 bitpack.PackBits(END_OF_PATCHES, 8);
227  
228 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
229 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
230  
231 return layer;
232 }
233  
234 public static void CreatePatch(BitPack output, float[] patchData, int x, int y)
235 {
236 if (patchData.Length != 16 * 16)
237 throw new ArgumentException("Patch data must be a 16x16 array");
238  
239 TerrainPatch.Header header = PrescanPatch(patchData);
240 header.QuantWBits = 136;
241 header.PatchIDs = (y & 0x1F);
242 header.PatchIDs += (x << 5);
243  
244 // NOTE: No idea what prequant and postquant should be or what they do
245 int[] patch = CompressPatch(patchData, header, 10);
246 int wbits = EncodePatchHeader(output, header, patch);
247 EncodePatch(output, patch, 0, wbits);
248 }
249  
250 public static void CreatePatch(BitPack output, float[,] patchData, int x, int y)
251 {
252 if (patchData.Length != 16 * 16)
253 throw new ArgumentException("Patch data must be a 16x16 array");
254  
255 TerrainPatch.Header header = PrescanPatch(patchData);
256 header.QuantWBits = 136;
257 header.PatchIDs = (y & 0x1F);
258 header.PatchIDs += (x << 5);
259  
260 // NOTE: No idea what prequant and postquant should be or what they do
261 int[] patch = CompressPatch(patchData, header, 10);
262 int wbits = EncodePatchHeader(output, header, patch);
263 EncodePatch(output, patch, 0, wbits);
264 }
265  
266 /// <summary>
267 /// Add a patch of terrain to a BitPacker
268 /// </summary>
269 /// <param name="output">BitPacker to write the patch to</param>
270 /// <param name="heightmap">Heightmap of the simulator, must be a 256 *
271 /// 256 float array</param>
272 /// <param name="x">X offset of the patch to create, valid values are
273 /// from 0 to 15</param>
274 /// <param name="y">Y offset of the patch to create, valid values are
275 /// from 0 to 15</param>
276 public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y)
277 {
278 if (heightmap.Length != 256 * 256)
279 throw new ArgumentException("Heightmap data must be 256x256");
280  
281 if (x < 0 || x > 15 || y < 0 || y > 15)
282 throw new ArgumentException("X and Y patch offsets must be from 0 to 15");
283  
284 TerrainPatch.Header header = PrescanPatch(heightmap, x, y);
285 header.QuantWBits = 136;
286 header.PatchIDs = (y & 0x1F);
287 header.PatchIDs += (x << 5);
288  
289 // NOTE: No idea what prequant and postquant should be or what they do
290 int[] patch = CompressPatch(heightmap, x, y, header, 10);
291 int wbits = EncodePatchHeader(output, header, patch);
292 EncodePatch(output, patch, 0, wbits);
293 }
294  
295 private static TerrainPatch.Header PrescanPatch(float[] patch)
296 {
297 TerrainPatch.Header header = new TerrainPatch.Header();
298 float zmax = -99999999.0f;
299 float zmin = 99999999.0f;
300  
301 for (int j = 0; j < 16; j++)
302 {
303 for (int i = 0; i < 16; i++)
304 {
305 float val = patch[j * 16 + i];
306 if (val > zmax) zmax = val;
307 if (val < zmin) zmin = val;
308 }
309 }
310  
311 header.DCOffset = zmin;
312 header.Range = (int)((zmax - zmin) + 1.0f);
313  
314 return header;
315 }
316  
317 private static TerrainPatch.Header PrescanPatch(float[,] patch)
318 {
319 TerrainPatch.Header header = new TerrainPatch.Header();
320 float zmax = -99999999.0f;
321 float zmin = 99999999.0f;
322  
323 for (int j = 0; j < 16; j++)
324 {
325 for (int i = 0; i < 16; i++)
326 {
327 float val = patch[j, i];
328 if (val > zmax) zmax = val;
329 if (val < zmin) zmin = val;
330 }
331 }
332  
333 header.DCOffset = zmin;
334 header.Range = (int)((zmax - zmin) + 1.0f);
335  
336 return header;
337 }
338  
339 private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY)
340 {
341 TerrainPatch.Header header = new TerrainPatch.Header();
342 float zmax = -99999999.0f;
343 float zmin = 99999999.0f;
344  
345 for (int j = patchY * 16; j < (patchY + 1) * 16; j++)
346 {
347 for (int i = patchX * 16; i < (patchX + 1) * 16; i++)
348 {
349 float val = heightmap[j * 256 + i];
350 if (val > zmax) zmax = val;
351 if (val < zmin) zmin = val;
352 }
353 }
354  
355 header.DCOffset = zmin;
356 header.Range = (int)((zmax - zmin) + 1.0f);
357  
358 return header;
359 }
360  
361 public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
362 {
363 TerrainPatch.Header header = new TerrainPatch.Header();
364  
365 // Quantized word bits
366 header.QuantWBits = bitpack.UnpackBits(8);
367 if (header.QuantWBits == END_OF_PATCHES)
368 return header;
369  
370 // DC offset
371 header.DCOffset = bitpack.UnpackFloat();
372  
373 // Range
374 header.Range = bitpack.UnpackBits(16);
375  
376 // Patch IDs (10 bits)
377 header.PatchIDs = bitpack.UnpackBits(10);
378  
379 // Word bits
380 header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2);
381  
382 return header;
383 }
384  
385 private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch)
386 {
387 int temp;
388 int wbits = (header.QuantWBits & 0x0f) + 2;
389 uint maxWbits = (uint)wbits + 5;
390 uint minWbits = ((uint)wbits >> 1);
391  
392 wbits = (int)minWbits;
393  
394 for (int i = 0; i < patch.Length; i++)
395 {
396 temp = patch[i];
397  
398 if (temp != 0)
399 {
400 // Get the absolute value
401 if (temp < 0) temp *= -1;
402  
403 for (int j = (int)maxWbits; j > (int)minWbits; j--)
404 {
405 if ((temp & (1 << j)) != 0)
406 {
407 if (j > wbits) wbits = j;
408 break;
409 }
410 }
411 }
412 }
413  
414 wbits += 1;
415  
416 header.QuantWBits &= 0xf0;
417  
418 if (wbits > 17 || wbits < 2)
419 {
420 Logger.Log("Bits needed per word in EncodePatchHeader() are outside the allowed range",
421 Helpers.LogLevel.Error);
422 }
423  
424 header.QuantWBits |= (wbits - 2);
425  
426 output.PackBits(header.QuantWBits, 8);
427 output.PackFloat(header.DCOffset);
428 output.PackBits(header.Range, 16);
429 output.PackBits(header.PatchIDs, 10);
430  
431 return wbits;
432 }
433  
434 private static void IDCTColumn16(float[] linein, float[] lineout, int column)
435 {
436 float total;
437 int usize;
438  
439 for (int n = 0; n < 16; n++)
440 {
441 total = OO_SQRT2 * linein[column];
442  
443 for (int u = 1; u < 16; u++)
444 {
445 usize = u * 16;
446 total += linein[usize + column] * CosineTable16[usize + n];
447 }
448  
449 lineout[16 * n + column] = total;
450 }
451 }
452  
453 private static void IDCTLine16(float[] linein, float[] lineout, int line)
454 {
455 const float oosob = 2.0f / 16.0f;
456 int lineSize = line * 16;
457 float total;
458  
459 for (int n = 0; n < 16; n++)
460 {
461 total = OO_SQRT2 * linein[lineSize];
462  
463 for (int u = 1; u < 16; u++)
464 {
465 total += linein[lineSize + u] * CosineTable16[u * 16 + n];
466 }
467  
468 lineout[lineSize + n] = total * oosob;
469 }
470 }
471  
472 private static void DCTLine16(float[] linein, float[] lineout, int line)
473 {
474 float total = 0.0f;
475 int lineSize = line * 16;
476  
477 for (int n = 0; n < 16; n++)
478 {
479 total += linein[lineSize + n];
480 }
481  
482 lineout[lineSize] = OO_SQRT2 * total;
483  
484 for (int u = 1; u < 16; u++)
485 {
486 total = 0.0f;
487  
488 for (int n = 0; n < 16; n++)
489 {
490 total += linein[lineSize + n] * CosineTable16[u * 16 + n];
491 }
492  
493 lineout[lineSize + u] = total;
494 }
495 }
496  
497 private static void DCTColumn16(float[] linein, int[] lineout, int column)
498 {
499 float total = 0.0f;
500 const float oosob = 2.0f / 16.0f;
501  
502 for (int n = 0; n < 16; n++)
503 {
504 total += linein[16 * n + column];
505 }
506  
507 lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
508  
509 for (int u = 1; u < 16; u++)
510 {
511 total = 0.0f;
512  
513 for (int n = 0; n < 16; n++)
514 {
515 total += linein[16 * n + column] * CosineTable16[u * 16 + n];
516 }
517  
518 lineout[CopyMatrix16[16 * u + column]] = (int)(total * oosob * QuantizeTable16[16 * u + column]);
519 }
520 }
521  
522 public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
523 {
524 int temp;
525 for (int n = 0; n < size * size; n++)
526 {
527 // ?
528 temp = bitpack.UnpackBits(1);
529 if (temp != 0)
530 {
531 // Value or EOB
532 temp = bitpack.UnpackBits(1);
533 if (temp != 0)
534 {
535 // Value
536 temp = bitpack.UnpackBits(1);
537 if (temp != 0)
538 {
539 // Negative
540 temp = bitpack.UnpackBits((int)header.WordBits);
541 patches[n] = temp * -1;
542 }
543 else
544 {
545 // Positive
546 temp = bitpack.UnpackBits((int)header.WordBits);
547 patches[n] = temp;
548 }
549 }
550 else
551 {
552 // Set the rest to zero
553 // TODO: This might not be necessary
554 for (int o = n; o < size * size; o++)
555 {
556 patches[o] = 0;
557 }
558 break;
559 }
560 }
561 else
562 {
563 patches[n] = 0;
564 }
565 }
566 }
567  
568 private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
569 {
570 int temp;
571 bool eob;
572  
573 if (postquant > 16 * 16 || postquant < 0)
574 {
575 Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
576 return;
577 }
578  
579 if (postquant != 0) patch[16 * 16 - postquant] = 0;
580  
581 for (int i = 0; i < 16 * 16; i++)
582 {
583 eob = false;
584 temp = patch[i];
585  
586 if (temp == 0)
587 {
588 eob = true;
589  
590 for (int j = i; j < 16 * 16 - postquant; j++)
591 {
592 if (patch[j] != 0)
593 {
594 eob = false;
595 break;
596 }
597 }
598  
599 if (eob)
600 {
601 output.PackBits(ZERO_EOB, 2);
602 return;
603 }
604 else
605 {
606 output.PackBits(ZERO_CODE, 1);
607 }
608 }
609 else
610 {
611 if (temp < 0)
612 {
613 temp *= -1;
614  
615 if (temp > (1 << wbits)) temp = (1 << wbits);
616  
617 output.PackBits(NEGATIVE_VALUE, 3);
618 output.PackBits(temp, wbits);
619 }
620 else
621 {
622 if (temp > (1 << wbits)) temp = (1 << wbits);
623  
624 output.PackBits(POSITIVE_VALUE, 3);
625 output.PackBits(temp, wbits);
626 }
627 }
628 }
629 }
630  
631 public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
632 {
633 float[] block = new float[group.PatchSize * group.PatchSize];
634 float[] output = new float[group.PatchSize * group.PatchSize];
635 int prequant = (header.QuantWBits >> 4) + 2;
636 int quantize = 1 << prequant;
637 float ooq = 1.0f / (float)quantize;
638 float mult = ooq * (float)header.Range;
639 float addval = mult * (float)(1 << (prequant - 1)) + header.DCOffset;
640  
641 if (group.PatchSize == 16)
642 {
643 for (int n = 0; n < 16 * 16; n++)
644 {
645 block[n] = patches[CopyMatrix16[n]] * DequantizeTable16[n];
646 }
647  
648 float[] ftemp = new float[16 * 16];
649  
650 for (int o = 0; o < 16; o++)
651 IDCTColumn16(block, ftemp, o);
652 for (int o = 0; o < 16; o++)
653 IDCTLine16(ftemp, block, o);
654 }
655 else
656 {
657 for (int n = 0; n < 32 * 32; n++)
658 {
659 block[n] = patches[CopyMatrix32[n]] * DequantizeTable32[n];
660 }
661  
662 Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
663 }
664  
665 for (int j = 0; j < block.Length; j++)
666 {
667 output[j] = block[j] * mult + addval;
668 }
669  
670 return output;
671 }
672  
673 private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant)
674 {
675 float[] block = new float[16 * 16];
676 int wordsize = prequant;
677 float oozrange = 1.0f / (float)header.Range;
678 float range = (float)(1 << prequant);
679 float premult = oozrange * range;
680 float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult;
681  
682 header.QuantWBits = wordsize - 2;
683 header.QuantWBits |= (prequant - 2) << 4;
684  
685 int k = 0;
686 for (int j = 0; j < 16; j++)
687 {
688 for (int i = 0; i < 16; i++)
689 block[k++] = patchData[j * 16 + i] * premult - sub;
690 }
691  
692 float[] ftemp = new float[16 * 16];
693 int[] itemp = new int[16 * 16];
694  
695 for (int o = 0; o < 16; o++)
696 DCTLine16(block, ftemp, o);
697 for (int o = 0; o < 16; o++)
698 DCTColumn16(ftemp, itemp, o);
699  
700 return itemp;
701 }
702  
703 private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant)
704 {
705 float[] block = new float[16 * 16];
706 int wordsize = prequant;
707 float oozrange = 1.0f / (float)header.Range;
708 float range = (float)(1 << prequant);
709 float premult = oozrange * range;
710 float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult;
711  
712 header.QuantWBits = wordsize - 2;
713 header.QuantWBits |= (prequant - 2) << 4;
714  
715 int k = 0;
716 for (int j = 0; j < 16; j++)
717 {
718 for (int i = 0; i < 16; i++)
719 block[k++] = patchData[j, i] * premult - sub;
720 }
721  
722 float[] ftemp = new float[16 * 16];
723 int[] itemp = new int[16 * 16];
724  
725 for (int o = 0; o < 16; o++)
726 DCTLine16(block, ftemp, o);
727 for (int o = 0; o < 16; o++)
728 DCTColumn16(ftemp, itemp, o);
729  
730 return itemp;
731 }
732  
733 private static int[] CompressPatch(float[] heightmap, int patchX, int patchY, TerrainPatch.Header header, int prequant)
734 {
735 float[] block = new float[16 * 16];
736 int wordsize = prequant;
737 float oozrange = 1.0f / (float)header.Range;
738 float range = (float)(1 << prequant);
739 float premult = oozrange * range;
740 float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult;
741  
742 header.QuantWBits = wordsize - 2;
743 header.QuantWBits |= (prequant - 2) << 4;
744  
745 int k = 0;
746 for (int j = patchY * 16; j < (patchY + 1) * 16; j++)
747 {
748 for (int i = patchX * 16; i < (patchX + 1) * 16; i++)
749 block[k++] = heightmap[j * 256 + i] * premult - sub;
750 }
751  
752 float[] ftemp = new float[16 * 16];
753 int[] itemp = new int[16 * 16];
754  
755 for (int o = 0; o < 16; o++)
756 DCTLine16(block, ftemp, o);
757 for (int o = 0; o < 16; o++)
758 DCTColumn16(ftemp, itemp, o);
759  
760 return itemp;
761 }
762  
763  
764 #region Initialization
765  
766 private static void BuildDequantizeTable16()
767 {
768 for (int j = 0; j < 16; j++)
769 {
770 for (int i = 0; i < 16; i++)
771 {
772 DequantizeTable16[j * 16 + i] = 1.0f + 2.0f * (float)(i + j);
773 }
774 }
775 }
776  
777 private static void BuildQuantizeTable16()
778 {
779 for (int j = 0; j < 16; j++)
780 {
781 for (int i = 0; i < 16; i++)
782 {
783 QuantizeTable16[j * 16 + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
784 }
785 }
786 }
787  
788 private static void SetupCosines16()
789 {
790 const float hposz = (float)Math.PI * 0.5f / 16.0f;
791  
792 for (int u = 0; u < 16; u++)
793 {
794 for (int n = 0; n < 16; n++)
795 {
796 CosineTable16[u * 16 + n] = (float)Math.Cos((2.0f * (float)n + 1.0f) * (float)u * hposz);
797 }
798 }
799 }
800  
801 private static void BuildCopyMatrix16()
802 {
803 bool diag = false;
804 bool right = true;
805 int i = 0;
806 int j = 0;
807 int count = 0;
808  
809 while (i < 16 && j < 16)
810 {
811 CopyMatrix16[j * 16 + i] = count++;
812  
813 if (!diag)
814 {
815 if (right)
816 {
817 if (i < 16 - 1) i++;
818 else j++;
819  
820 right = false;
821 diag = true;
822 }
823 else
824 {
825 if (j < 16 - 1) j++;
826 else i++;
827  
828 right = true;
829 diag = true;
830 }
831 }
832 else
833 {
834 if (right)
835 {
836 i++;
837 j--;
838 if (i == 16 - 1 || j == 0) diag = false;
839 }
840 else
841 {
842 i--;
843 j++;
844 if (j == 16 - 1 || i == 0) diag = false;
845 }
846 }
847 }
848 }
849  
850 #endregion Initialization
851 }
852 }