From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Region/Framework/Scenes/TerrainCompressor.cs | 1611 ++++++++++++-------- 1 file changed, 994 insertions(+), 617 deletions(-) (limited to 'OpenSim/Region/Framework/Scenes/TerrainCompressor.cs') diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs index fc8f8cd..9d1f815 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs @@ -27,10 +27,13 @@ /* Freely adapted from the Aurora version of the terrain compressor. * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/ + * Aurora version created from libOpenMetaverse Library terrain compressor */ using System; +using System.Collections.Generic; using System.Reflection; +using System.Diagnostics; using log4net; @@ -45,7 +48,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { public static class OpenSimTerrainCompressor { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #pragma warning disable 414 private static string LogHeader = "[TERRAIN COMPRESSOR]"; @@ -61,47 +64,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP private const int POSITIVE_VALUE = 0x6; private const int NEGATIVE_VALUE = 0x7; - private static readonly float[] DequantizeTable16 = - new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - - private static readonly float[] DequantizeTable32 = - new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; - private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; +// private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; private static readonly float[] QuantizeTable16 = - new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + private static readonly float[] DequantizeTable16 = + new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; static OpenSimTerrainCompressor() { // Initialize the decompression tables BuildDequantizeTable16(); - SetupCosines16(); +// SetupCosines16(); BuildCopyMatrix16(); BuildQuantizeTable16(); } // Used to send cloud and wind patches - public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX, - int pRegionSizeY) + public static LayerDataPacket CreateLayerDataPacketStandardSize(TerrainPatch[] patches, byte type) { - LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; + LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = type } }; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader - {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize}; + { Stride = STRIDE, PatchSize = Constants.TerrainPatchSize }; // Should be enough to fit even the most poorly packed data - byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2]; + byte[] data = new byte[patches.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits(type, 8); foreach (TerrainPatch t in patches) - CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY); + CreatePatchtStandardSize(bitpack, t.Data, t.X, t.Y); bitpack.PackBits(END_OF_PATCHES, 8); @@ -111,122 +108,131 @@ namespace OpenSim.Region.ClientStack.LindenUDP return layer; } - // Create a land packet for a single patch. - public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY) + public static void CreatePatchtStandardSize(BitPack output, float[] patchData, int x, int y) { - int[] xPieces = new int[1]; - int[] yPieces = new int[1]; - xPieces[0] = patchX; // patch X dimension - yPieces[0] = patchY; + TerrainPatch.Header header = PrescanPatch(patchData); + header.QuantWBits = 136; + + header.PatchIDs = (y & 0x1F); + header.PatchIDs += (x << 5); - return CreateLandPacket(terrData, xPieces, yPieces); + int wbits; + int[] patch = CompressPatch(patchData, header, 10, out wbits); + EncodePatchHeader(output, header, patch, false, ref wbits); + EncodePatch(output, patch, 0, wbits); } - public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces) + private static TerrainPatch.Header PrescanPatch(float[] patch) { - byte landPacketType = (byte)TerrainPatch.LayerType.Land; - if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) + TerrainPatch.Header header = new TerrainPatch.Header(); + float zmax = -99999999.0f; + float zmin = 99999999.0f; + + for (int i = 0; i < Constants.TerrainPatchSize * Constants.TerrainPatchSize; i++) { - landPacketType = (byte)TerrainPatch.LayerType.LandExtended; + float val = patch[i]; + if (val > zmax) zmax = val; + if (val < zmin) zmin = val; } - return CreateLandPacket(terrData, xPieces, yPieces, landPacketType); + header.DCOffset = zmin; + header.Range = (int)((zmax - zmin) + 1.0f); + + return header; } - /// - /// Creates a LayerData packet for compressed land data given a full - /// simulator heightmap and an array of indices of patches to compress - /// - /// - /// Terrain data that can result in a meter square heightmap. - /// - /// - /// Array of indexes in the grid of patches - /// for this simulator. - /// If creating a packet for multiple patches, there will be entries in - /// both the X and Y arrays for each of the patches. - /// For example if patches 1 and 17 are to be sent, - /// x[] = {1,1} and y[] = {0,1} which specifies the patches at - /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches). - /// - /// - /// Array of indexes in the grid of patches. - /// - /// - /// - public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type) + private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits) { - LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; + float[] block = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + float oozrange = 1.0f / header.Range; + float range = (1 << prequant); + float premult = oozrange * range; - TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader - {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize}; - byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; - BitPack bitpack = new BitPack(data, 0); - bitpack.PackBits(header.Stride, 16); - bitpack.PackBits(header.PatchSize, 8); - bitpack.PackBits(type, 8); + float sub = 0.5f * header.Range + header.DCOffset; - for (int i = 0; i < x.Length; i++) - CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]); + int wordsize = (prequant - 2) & 0x0f; + header.QuantWBits = wordsize; + header.QuantWBits |= wordsize << 4; - bitpack.PackBits(END_OF_PATCHES, 8); + int k = 0; + for (int j = 0; j < Constants.TerrainPatchSize; j++) + { + for (int i = 0; i < Constants.TerrainPatchSize; i++) + block[k++] = (patchData[j * Constants.TerrainPatchSize + i] - sub) * premult; + } - layer.LayerData.Data = new byte[bitpack.BytePos + 1]; - Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + float[] ftemp = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + int[] iout = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; - return layer; + wbits = (prequant >> 1); + + dct16x16(block, iout, ref wbits); + + return iout; } - // Unused: left for historical reference. - public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY) + // new using terrain data and patchs indexes + public static List CreateLayerDataPackets(TerrainData terrData, int[] x, int[] y, byte landPacketType) { - TerrainPatch.Header header = PrescanPatch(patchData); - header.QuantWBits = 136; - if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) - { - header.PatchIDs = (y & 0xFFFF); - header.PatchIDs += (x << 16); - } - else + List ret = new List(); + + //create packet and global header + LayerDataPacket layer = new LayerDataPacket(); + + layer.LayerID.Type = landPacketType; + + byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; + BitPack bitpack = new BitPack(data, 0); + bitpack.PackBits(STRIDE, 16); + bitpack.PackBits(Constants.TerrainPatchSize, 8); + bitpack.PackBits(landPacketType, 8); + + for (int i = 0; i < x.Length; i++) { - header.PatchIDs = (y & 0x1F); - header.PatchIDs += (x << 5); + CreatePatchFromTerrainData(bitpack, terrData, x[i], y[i]); + if (bitpack.BytePos > 980 && i != x.Length - 1) + { + //finish this packet + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + ret.Add(layer); + + // start another + layer = new LayerDataPacket(); + layer.LayerID.Type = landPacketType; + + bitpack = new BitPack(data, 0); + bitpack.PackBits(STRIDE, 16); + bitpack.PackBits(Constants.TerrainPatchSize, 8); + bitpack.PackBits(landPacketType, 8); + } } - // NOTE: No idea what prequant and postquant should be or what they do + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + ret.Add(layer); - int wbits; - int[] patch = CompressPatch(patchData, header, 10, out wbits); - wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits); - EncodePatch(output, patch, 0, wbits); + return ret; } - /// - /// Add a patch of terrain to a BitPacker - /// - /// BitPacker to write the patch to - /// - /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array. - /// - /// - /// X offset of the patch to create. - /// - /// - /// Y offset of the patch to create. - /// - /// - /// - public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY) + public static void CreatePatchFromTerrainData(BitPack output, TerrainData terrData, int patchX, int patchY) { - TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY); - header.QuantWBits = 136; + float frange; + TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY, out frange); + header.QuantWBits = 130; + bool largeRegion = false; // If larger than legacy region size, pack patch X and Y info differently. if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) { header.PatchIDs = (patchY & 0xFFFF); header.PatchIDs += (patchX << 16); + largeRegion = true; } else { @@ -234,45 +240,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP header.PatchIDs += (patchX << 5); } - // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}", - // LogHeader, patchX, patchY, header.DCOffset, header.Range); + if (Math.Round((double)frange, 2) == 1.0) + { + // flat terrain speed up things - // NOTE: No idea what prequant and postquant should be or what they do - int wbits; - int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits); - wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits); - EncodePatch(output, patch, 0, wbits); - } + header.DCOffset -= 0.5f; - private static TerrainPatch.Header PrescanPatch(float[] patch) - { - TerrainPatch.Header header = new TerrainPatch.Header(); - float zmax = -99999999.0f; - float zmin = 99999999.0f; + header.QuantWBits = 0x00; + output.PackBits(header.QuantWBits, 8); + output.PackFloat(header.DCOffset); + output.PackBits(1, 16); + if (largeRegion) + output.PackBits(header.PatchIDs, 32); + else + output.PackBits(header.PatchIDs, 10); - for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) - { - float val = patch[i]; - if (val > zmax) zmax = val; - if (val < zmin) zmin = val; + // and thats all + output.PackBits(ZERO_EOB, 2); + return; } - header.DCOffset = zmin; - header.Range = (int) ((zmax - zmin) + 1.0f); - - return header; + int wbits; + int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits); + EncodePatchHeader(output, header, patch, largeRegion, ref wbits); + EncodePatch(output, patch, 0, wbits); } // Scan the height info we're returning and return a patch packet header for this patch. - private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY) + private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY, out float frange) { TerrainPatch.Header header = new TerrainPatch.Header(); - float zmax = -99999999.0f; - float zmin = 99999999.0f; + float zmax = float.MinValue; + float zmin = float.MaxValue; + + int startx = patchX * Constants.TerrainPatchSize; + int starty = patchY * Constants.TerrainPatchSize; - for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++) + for (int j = starty; j < starty + Constants.TerrainPatchSize; j++) { - for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++) + for (int i = startx; i < startx + Constants.TerrainPatchSize; i++) { float val = terrData[i, j]; if (val > zmax) zmax = val; @@ -281,309 +287,385 @@ namespace OpenSim.Region.ClientStack.LindenUDP } header.DCOffset = zmin; - header.Range = (int)((zmax - zmin) + 1.0f); - - return header; - } - - public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) - { - TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)}; - - // Quantized word bits - if (header.QuantWBits == END_OF_PATCHES) - return header; - - // DC offset - header.DCOffset = bitpack.UnpackFloat(); - - // Range - header.Range = bitpack.UnpackBits(16); - - // Patch IDs (10 bits) - header.PatchIDs = bitpack.UnpackBits(10); - - // Word bits - header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2); + frange = ((zmax - zmin) + 1.0f); + header.Range = (int)frange; return header; } - private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX, - uint pRegionSizeY, int wbits) + private static void EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, bool largeRegion, ref int wbits) { - /* - int temp; - int wbits = (header.QuantWBits & 0x0f) + 2; - uint maxWbits = (uint)wbits + 5; - uint minWbits = ((uint)wbits >> 1); - int wbitsMaxValue; - */ - // goal is to determ minimum number of bits to use so all data fits - /* - wbits = (int)minWbits; - wbitsMaxValue = (1 << wbits); - - for (int i = 0; i < patch.Length; i++) - { - temp = patch[i]; - if (temp != 0) - { - // Get the absolute value - if (temp < 0) temp *= -1; - - no coments.. - - for (int j = (int)maxWbits; j > (int)minWbits; j--) - { - if ((temp & (1 << j)) != 0) - { - if (j > wbits) wbits = j; - break; - } - } - - while (temp > wbitsMaxValue) - { - wbits++; - if (wbits == maxWbits) - goto Done; - wbitsMaxValue = 1 << wbits; - } - } - } - - Done: - - // wbits += 1; - */ - // better check if (wbits > 17) - wbits = 16; - else if (wbits < 3) - wbits = 3; + wbits = 17; + else if (wbits < 2) + wbits = 2; header.QuantWBits &= 0xf0; - header.QuantWBits |= (wbits - 2); output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); - if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) + if (largeRegion) output.PackBits(header.PatchIDs, 32); else output.PackBits(header.PatchIDs, 10); - - return wbits; } - private static void IDCTColumn16(float[] linein, float[] lineout, int column) + private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) { - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - float total = OO_SQRT2*linein[column]; - - for (int u = 1; u < Constants.TerrainPatchSize; u++) - { - int usize = u*Constants.TerrainPatchSize; - total += linein[usize + column]*CosineTable16[usize + n]; - } + int maxwbitssize = (1 << wbits) - 1; + int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; - lineout[Constants.TerrainPatchSize*n + column] = total; + if (postquant > fullSize || postquant < 0) + { + Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); + return; } - } - private static void IDCTLine16(float[] linein, float[] lineout, int line) - { - const float oosob = 2.0f/Constants.TerrainPatchSize; - int lineSize = line*Constants.TerrainPatchSize; + if (postquant != 0) + patch[fullSize - postquant] = 0; - for (int n = 0; n < Constants.TerrainPatchSize; n++) + int lastZeroindx = fullSize - postquant; + + for (int i = 0; i < fullSize; i++) { - float total = OO_SQRT2*linein[lineSize]; + int temp = patch[i]; - for (int u = 1; u < Constants.TerrainPatchSize; u++) + if (temp == 0) { - total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n]; - } - - lineout[lineSize + n] = total*oosob; - } - } + bool eob = true; -/* - private static void DCTLine16(float[] linein, float[] lineout, int line) - { - float total = 0.0f; - int lineSize = line * Constants.TerrainPatchSize; + for (int j = i; j < lastZeroindx; j++) + { + if (patch[j] != 0) + { + eob = false; + break; + } + } - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[lineSize + n]; - } + if (eob) + { + output.PackBits(ZERO_EOB, 2); + return; + } + output.PackBits(ZERO_CODE, 1); + } + else + { + if (temp < 0) + { + temp *= -1; - lineout[lineSize] = OO_SQRT2 * total; + if (temp > maxwbitssize) temp = maxwbitssize; - int uptr = 0; - for (int u = 1; u < Constants.TerrainPatchSize; u++) - { - total = 0.0f; - uptr += Constants.TerrainPatchSize; + output.PackBits(NEGATIVE_VALUE, 3); + output.PackBits(temp, wbits); + } + else + { + if (temp > maxwbitssize) temp = maxwbitssize; - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[lineSize + n] * CosineTable16[uptr + n]; + output.PackBits(POSITIVE_VALUE, 3); + output.PackBits(temp, wbits); + } } - - lineout[lineSize + u] = total; } } -*/ - private static void DCTLine16(float[] linein, float[] lineout, int line) + private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header, + int prequant, out int wbits) { - // outputs transpose data (lines exchanged with coluns ) - // so to save a bit of cpu when doing coluns - float total = 0.0f; - int lineSize = line*Constants.TerrainPatchSize; + float[] block = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + int[] iout = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[lineSize + n]; - } + float oozrange = 1.0f / header.Range; + float invprequat = (1 << prequant); + float premult = oozrange * invprequat; - lineout[line] = OO_SQRT2*total; + float sub = 0.5f * header.Range + header.DCOffset; + + int wordsize = (prequant - 2) & 0x0f; + header.QuantWBits = wordsize; + header.QuantWBits |= wordsize << 4; - for (int u = Constants.TerrainPatchSize; - u < Constants.TerrainPatchSize*Constants.TerrainPatchSize; - u += Constants.TerrainPatchSize) + int k = 0; + int startX = patchX * Constants.TerrainPatchSize; + int startY = patchY * Constants.TerrainPatchSize; + for (int y = startY; y < startY + Constants.TerrainPatchSize; y++) { - total = 0.0f; - for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++) + for (int x = startX; x < startX + Constants.TerrainPatchSize; x++) { - total += linein[ptrn]*CosineTable16[ptru]; + block[k++] = (terrData[x, y] - sub) * premult; } - - lineout[line + u] = total; } - } - - - /* - private static void DCTColumn16(float[] linein, int[] lineout, int column) - { - float total = 0.0f; - // const float oosob = 2.0f / Constants.TerrainPatchSize; - - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[Constants.TerrainPatchSize * n + column]; - } - // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); - lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]); + wbits = (prequant >> 1); - for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize) - { - total = 0.0f; + dct16x16(block, iout, ref wbits); - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n]; - } + return iout; + } - // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]); - lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]); - } - } + #region Initialization - private static void DCTColumn16(float[] linein, int[] lineout, int column) + private static void BuildDequantizeTable16() { - // input columns are in fact stored in lines now - - float total = 0.0f; -// const float oosob = 2.0f / Constants.TerrainPatchSize; - int inlinesptr = Constants.TerrainPatchSize*column; - - for (int n = 0; n < Constants.TerrainPatchSize; n++) + for (int j = 0; j < Constants.TerrainPatchSize; j++) { - total += linein[inlinesptr + n]; + for (int i = 0; i < Constants.TerrainPatchSize; i++) + { + DequantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f + 2.0f * (i + j); + } } + } - // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); - lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]); - - for (int uptr = Constants.TerrainPatchSize; - uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize; - uptr += Constants.TerrainPatchSize) + private static void BuildQuantizeTable16() + { + const float oosob = 2.0f / Constants.TerrainPatchSize; + for (int j = 0; j < Constants.TerrainPatchSize; j++) { - total = 0.0f; - - for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++) + for (int i = 0; i < Constants.TerrainPatchSize; i++) { - total += linein[n]*CosineTable16[ptru]; + QuantizeTable16[j * Constants.TerrainPatchSize + i] = oosob / (1.0f + 2.0f * (i + (float)j)); } - -// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]); - lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]); } } - */ - private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits) + private static void BuildCopyMatrix16() { - // input columns are in fact stored in lines now - - bool dowbits = wbits != maxwbits; - int wbitsMaxValue = 1 << wbits; - - float total = 0.0f; - // const float oosob = 2.0f / Constants.TerrainPatchSize; - int inlinesptr = Constants.TerrainPatchSize*column; + bool diag = false; + bool right = true; + int i = 0; + int j = 0; + int count = 0; - for (int n = 0; n < Constants.TerrainPatchSize; n++) + while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize) { - total += linein[inlinesptr + n]; - } - - // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); - int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]); - lineout[CopyMatrix16[column]] = tmp; + CopyMatrix16[j * Constants.TerrainPatchSize + i] = count++; - if (dowbits) - { - if (tmp < 0) tmp *= -1; - while (tmp > wbitsMaxValue) + if (!diag) { - wbits++; - wbitsMaxValue = 1 << wbits; - if (wbits == maxwbits) + if (right) { - dowbits = false; - break; - } - } - } + if (i < Constants.TerrainPatchSize - 1) i++; + else j++; - for (int uptr = Constants.TerrainPatchSize; - uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize; - uptr += Constants.TerrainPatchSize) - { - total = 0.0f; + right = false; + diag = true; + } + else + { + if (j < Constants.TerrainPatchSize - 1) j++; + else i++; - for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++) + right = true; + diag = true; + } + } + else { - total += linein[n]*CosineTable16[ptru]; + if (right) + { + i++; + j--; + if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false; + } + else + { + i--; + j++; + if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false; + } } + } + } + + #endregion Initialization + + + + + #region DCT + + /* DCT (Discrete Cosine Transform) + adaptation from + General Purpose 2D,3D FFT (Fast Fourier Transform) Package + by Takuya OOURA (email: ooura@kurims.kyoto-u.ac.jp) + + -------- 16x16 DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + Normalized 16x16 IDCT + C[k1 + k2] = (1/8) * sum_j1=0^15 sum_j2=0^15 + tmp[j1 + j2] * s[j1] * s[j2] * + cos(pi*j1*(k1+1/2)/16) * + cos(pi*j2*(k2+1/2)/16), 0<=k1<16, 0<=k2<16 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + Normalized 16x16 DCT + C[k1 + k2] = (1/8) * s[k1] * s[k2] * sum_j1=0^15 sum_j2=0^15 + tmp[j1 + j2] * + cos(pi*(j1+1/2)*k1/16) * + cos(pi*(j2+1/2)*k2/16), 0<=k1<16, 0<=k2<16 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + */ + + /* Cn_kR = sqrt(2.0/n) * cos(pi/2*k/n) */ + /* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */ + /* Wn_kR = cos(pi/2*k/n) */ + /* Wn_kI = sin(pi/2*k/n) */ + + const float C16_1R = 0.35185093438159561476f * 2.82842712474619f; + const float C16_1I = 0.03465429229977286565f * 2.82842712474619f; + const float C16_2R = 0.34675996133053686546f * 2.82842712474619f; + const float C16_2I = 0.06897484482073575308f * 2.82842712474619f; + const float C16_3R = 0.33832950029358816957f * 2.82842712474619f; + const float C16_3I = 0.10263113188058934529f * 2.82842712474619f; + const float C16_4R = 0.32664074121909413196f * 2.82842712474619f; + const float C16_4I = 0.13529902503654924610f * 2.82842712474619f; + const float C16_5R = 0.31180625324666780814f * 2.82842712474619f; + const float C16_5I = 0.16666391461943662432f * 2.82842712474619f; + const float C16_6R = 0.29396890060483967924f * 2.82842712474619f; + const float C16_6I = 0.19642373959677554532f * 2.82842712474619f; + const float C16_7R = 0.27330046675043937206f * 2.82842712474619f; + const float C16_7I = 0.22429189658565907106f * 2.82842712474619f; + const float C16_8R = 0.25f * 2.82842712474619f; + const float W16_4R = 0.92387953251128675613f; + const float W16_4I = 0.38268343236508977173f; + const float W16_8R = 0.70710678118654752440f; + + static void dct16x16(float[] a, int[] iout, ref int wbits) + { + float[] tmp = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + float x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; + float xr, xi; + float ftmp; - tmp = (int) (total*QuantizeTable16[uptr + column]); - lineout[CopyMatrix16[uptr + column]] = tmp; + int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; + int itmp; + int j, k; + int indx; + + const int maxwbits = 17; // per header encoding + int wbitsMaxValue = 1 << wbits; + bool dowbits = wbits < 17; + + for (j = 0, k = 0; j < fullSize; j += Constants.TerrainPatchSize, k++) + { + x4r = a[0 + j] - a[15 + j]; + xr = a[0 + j] + a[15 + j]; + x4i = a[8 + j] - a[7 + j]; + xi = a[8 + j] + a[7 + j]; + x0r = xr + xi; + x0i = xr - xi; + x5r = a[2 + j] - a[13 + j]; + xr = a[2 + j] + a[13 + j]; + x5i = a[10 + j] - a[5 + j]; + xi = a[10 + j] + a[5 + j]; + x1r = xr + xi; + x1i = xr - xi; + x6r = a[4 + j] - a[11 + j]; + xr = a[4 + j] + a[11 + j]; + x6i = a[12 + j] - a[3 + j]; + xi = a[12 + j] + a[3 + j]; + x2r = xr + xi; + x2i = xr - xi; + x7r = a[6 + j] - a[9 + j]; + xr = a[6 + j] + a[9 + j]; + x7i = a[14 + j] - a[1 + j]; + xi = a[14 + j] + a[1 + j]; + x3r = xr + xi; + x3i = xr - xi; + xr = x0r + x2r; + xi = x1r + x3r; + tmp[k] = C16_8R * (xr + xi); // + tmp[8 * Constants.TerrainPatchSize + k] = C16_8R * (xr - xi); // + xr = x0r - x2r; + xi = x1r - x3r; + tmp[4 * Constants.TerrainPatchSize + k] = C16_4R * xr - C16_4I * xi; // + tmp[12 * Constants.TerrainPatchSize + k] = C16_4R * xi + C16_4I * xr; // + x0r = W16_8R * (x1i - x3i); + x2r = W16_8R * (x1i + x3i); + xr = x0i + x0r; + xi = x2r + x2i; + tmp[2 * Constants.TerrainPatchSize + k] = C16_2R * xr - C16_2I * xi; // + tmp[14 * Constants.TerrainPatchSize + k] = C16_2R * xi + C16_2I * xr; // + xr = x0i - x0r; + xi = x2r - x2i; + tmp[6 * Constants.TerrainPatchSize + k] = C16_6R * xr - C16_6I * xi; // + tmp[10 * Constants.TerrainPatchSize + k] = C16_6R * xi + C16_6I * xr; // + xr = W16_8R * (x6r - x6i); + xi = W16_8R * (x6i + x6r); + x6r = x4r - xr; + x6i = x4i - xi; + x4r += xr; + x4i += xi; + xr = W16_4I * x7r - W16_4R * x7i; + xi = W16_4I * x7i + W16_4R * x7r; + x7r = W16_4R * x5r - W16_4I * x5i; + x7i = W16_4R * x5i + W16_4I * x5r; + x5r = x7r + xr; + x5i = x7i + xi; + x7r -= xr; + x7i -= xi; + xr = x4r + x5r; + xi = x5i + x4i; + tmp[Constants.TerrainPatchSize + k] = C16_1R * xr - C16_1I * xi; // + tmp[15 * Constants.TerrainPatchSize + k] = C16_1R * xi + C16_1I * xr; // + xr = x4r - x5r; + xi = x5i - x4i; + tmp[7 * Constants.TerrainPatchSize + k] = C16_7R * xr - C16_7I * xi; // + tmp[9 * Constants.TerrainPatchSize + k] = C16_7R * xi + C16_7I * xr; // + xr = x6r - x7i; + xi = x7r + x6i; + tmp[5 * Constants.TerrainPatchSize + k] = C16_5R * xr - C16_5I * xi; // + tmp[11 * Constants.TerrainPatchSize + k] = C16_5R * xi + C16_5I * xr; // + xr = x6r + x7i; + xi = x7r - x6i; + tmp[3 * Constants.TerrainPatchSize + k] = C16_3R * xr - C16_3I * xi; // + tmp[13 * Constants.TerrainPatchSize + k] = C16_3R * xi + C16_3I * xr; // + } + + for (j = 0, k = 0; j < fullSize; j += Constants.TerrainPatchSize, k++) + { + x4r = tmp[0 + j] - tmp[15 + j]; + xr = tmp[0 + j] + tmp[15 + j]; + x4i = tmp[8 + j] - tmp[7 + j]; + xi = tmp[8 + j] + tmp[7 + j]; + x0r = xr + xi; + x0i = xr - xi; + x5r = tmp[2 + j] - tmp[13 + j]; + xr = tmp[2 + j] + tmp[13 + j]; + x5i = tmp[10 + j] - tmp[5 + j]; + xi = tmp[10 + j] + tmp[5 + j]; + x1r = xr + xi; + x1i = xr - xi; + x6r = tmp[4 + j] - tmp[11 + j]; + xr = tmp[4 + j] + tmp[11 + j]; + x6i = tmp[12 + j] - tmp[3 + j]; + xi = tmp[12 + j] + tmp[3 + j]; + x2r = xr + xi; + x2i = xr - xi; + x7r = tmp[6 + j] - tmp[9 + j]; + xr = tmp[6 + j] + tmp[9 + j]; + x7i = tmp[14 + j] - tmp[1 + j]; + xi = tmp[14 + j] + tmp[1 + j]; + x3r = xr + xi; + x3i = xr - xi; + xr = x0r + x2r; + xi = x1r + x3r; + + //tmp[0 + k] = C16_8R * (xr + xi); // + ftmp = C16_8R * (xr + xi); + itmp = (int)(ftmp * QuantizeTable16[k]); + iout[CopyMatrix16[k]] = itmp; if (dowbits) { - if (tmp < 0) tmp *= -1; - while (tmp > wbitsMaxValue) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { wbits++; wbitsMaxValue = 1 << wbits; @@ -594,355 +676,650 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } } - } - return wbits; - } - public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) - { - for (int n = 0; n < size*size; n++) - { - // ? - int temp = bitpack.UnpackBits(1); - if (temp != 0) + //tmp[8 * Constants.TerrainPatchSize + k] = C16_8R * (xr - xi); // + ftmp = C16_8R * (xr - xi); + indx = 8 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) { - // Value or EOB - temp = bitpack.UnpackBits(1); - if (temp != 0) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - // Value - temp = bitpack.UnpackBits(1); - if (temp != 0) - { - // Negative - temp = bitpack.UnpackBits((int) header.WordBits); - patches[n] = temp*-1; - } - else + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) { - // Positive - temp = bitpack.UnpackBits((int) header.WordBits); - patches[n] = temp; + dowbits = false; + break; } } - else + } + + xr = x0r - x2r; + xi = x1r - x3r; + + //tmp[4 * Constants.TerrainPatchSize + k] = C16_4R * xr - C16_4I * xi; // + ftmp = C16_4R * xr - C16_4I * xi; + indx = 4 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - // Set the rest to zero - // TODO: This might not be necessary - for (int o = n; o < size*size; o++) + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) { - patches[o] = 0; + dowbits = false; + break; } - break; } } - else - { - patches[n] = 0; - } - } - } - private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) - { - int maxwbitssize = (1 << wbits) - 1; + //tmp[12 * Constants.TerrainPatchSize + k] = C16_4R * xi + C16_4I * xr; // + ftmp = C16_4R * xi + C16_4I * xr; + indx = 12 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0) - { - Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); - return; - } + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0; + x0r = W16_8R * (x1i - x3i); + x2r = W16_8R * (x1i + x3i); + xr = x0i + x0r; + xi = x2r + x2i; - for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) - { - int temp = patch[i]; + //tmp[2 * Constants.TerrainPatchSize + k] = C16_2R * xr - C16_2I * xi; // + ftmp = C16_2R * xr - C16_2I * xi; + indx = 2 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - if (temp == 0) + if (dowbits) { - bool eob = true; - - for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - if (patch[j] != 0) + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) { - eob = false; + dowbits = false; break; } } + } - if (eob) + //tmp[14 * Constants.TerrainPatchSize + k] = C16_2R * xi + C16_2I * xr; // + ftmp = C16_2R * xi + C16_2I * xr; + indx = 14 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - output.PackBits(ZERO_EOB, 2); - return; + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } } - output.PackBits(ZERO_CODE, 1); } - else + + xr = x0i - x0r; + xi = x2r - x2i; + + //tmp[6 * Constants.TerrainPatchSize + k] = C16_6R * xr - C16_6I * xi; // + ftmp = C16_6R * xr - C16_6I * xi; + indx = 6 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) { - if (temp < 0) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - temp *= -1; + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - if (temp > maxwbitssize) temp = maxwbitssize; + //tmp[10 * Constants.TerrainPatchSize + k] = C16_6R * xi + C16_6I * xr; // + ftmp = C16_6R * xi + C16_6I * xr; + indx = 10 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - output.PackBits(NEGATIVE_VALUE, 3); - output.PackBits(temp, wbits); - } - else + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - if (temp > maxwbitssize) temp = maxwbitssize; - - output.PackBits(POSITIVE_VALUE, 3); - output.PackBits(temp, wbits); + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } } } - } - } - public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group) - { - float[] block = new float[group.PatchSize*group.PatchSize]; - float[] output = new float[group.PatchSize*group.PatchSize]; - int prequant = (header.QuantWBits >> 4) + 2; - int quantize = 1 << prequant; - float ooq = 1.0f/quantize; - float mult = ooq*header.Range; - float addval = mult*(1 << (prequant - 1)) + header.DCOffset; - - if (group.PatchSize == Constants.TerrainPatchSize) - { - for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++) + xr = W16_8R * (x6r - x6i); + xi = W16_8R * (x6i + x6r); + x6r = x4r - xr; + x6i = x4i - xi; + x4r += xr; + x4i += xi; + xr = W16_4I * x7r - W16_4R * x7i; + xi = W16_4I * x7i + W16_4R * x7r; + x7r = W16_4R * x5r - W16_4I * x5i; + x7i = W16_4R * x5i + W16_4I * x5r; + x5r = x7r + xr; + x5i = x7i + xi; + x7r -= xr; + x7i -= xi; + xr = x4r + x5r; + xi = x5i + x4i; + + //tmp[1 * Constants.TerrainPatchSize + k] = C16_1R * xr - C16_1I * xi; // + ftmp = C16_1R * xr - C16_1I * xi; + indx = Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) { - block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n]; + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } } - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + //tmp[15 * Constants.TerrainPatchSize + k] = C16_1R * xi + C16_1I * xr; // + ftmp = C16_1R * xi + C16_1I * xr; + indx = 15 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - for (int o = 0; o < Constants.TerrainPatchSize; o++) - IDCTColumn16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - IDCTLine16(ftemp, block, o); - } - else - { - for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++) + if (dowbits) { - block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n]; + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } } - Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error); - } + xr = x4r - x5r; + xi = x5i - x4i; - for (int j = 0; j < block.Length; j++) - { - output[j] = block[j]*mult + addval; - } + //tmp[7 * Constants.TerrainPatchSize + k] = C16_7R * xr - C16_7I * xi; // + ftmp = C16_7R * xr - C16_7I * xi; + indx = 7 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - return output; - } + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits) - { - float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int wordsize = (prequant - 2) & 0x0f; - float oozrange = 1.0f/header.Range; - float range = (1 << prequant); - float premult = oozrange*range; - float sub = (1 << (prequant - 1)) + header.DCOffset*premult; + //tmp[9 * Constants.TerrainPatchSize + k] = C16_7R * xi + C16_7I * xr; // + ftmp = C16_7R * xi + C16_7I * xr; + indx = 9 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - header.QuantWBits = wordsize; - header.QuantWBits |= wordsize << 4; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - int k = 0; - for (int j = 0; j < Constants.TerrainPatchSize; j++) - { - for (int i = 0; i < Constants.TerrainPatchSize; i++) - block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub; - } + xr = x6r - x7i; + xi = x7r + x6i; - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + //tmp[5 * Constants.TerrainPatchSize + k] = C16_5R * xr - C16_5I * xi; // + ftmp = C16_5R * xr - C16_5I * xi; + indx = 5 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - int maxWbits = prequant + 5; - wbits = (prequant >> 1); + //tmp[11 * Constants.TerrainPatchSize + k] = C16_5R * xi + C16_5I * xr; // + ftmp = C16_5R * xi + C16_5I * xr; + indx = 11 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - for (int o = 0; o < Constants.TerrainPatchSize; o++) - DCTLine16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - return itemp; - } + xr = x6r + x7i; + xi = x7r - x6i; - private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits) - { - float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - float oozrange = 1.0f/header.Range; - float range = (1 << prequant); - float premult = oozrange*range; - float sub = (1 << (prequant - 1)) + header.DCOffset*premult; - int wordsize = (prequant - 2) & 0x0f; + //tmp[3 * Constants.TerrainPatchSize + k] = C16_3R * xr - C16_3I * xi; // + ftmp = C16_3R * xr - C16_3I * xi; + indx = 3 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - header.QuantWBits = wordsize; - header.QuantWBits |= wordsize << 4; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - int k = 0; - for (int j = 0; j < Constants.TerrainPatchSize; j++) - { - for (int i = 0; i < Constants.TerrainPatchSize; i++) - block[k++] = patchData[j, i]*premult - sub; - } + //tmp[13 * Constants.TerrainPatchSize + k] = C16_3R * xi + C16_3I * xr; // + ftmp = C16_3R * xi + C16_3I * xr; + indx = 13 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } + } + } - int maxWbits = prequant + 5; - wbits = (prequant >> 1); + #endregion DCT - for (int o = 0; o < Constants.TerrainPatchSize; o++) - DCTLine16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); + #region Decode + /* + public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) + { + TerrainPatch.Header header = new TerrainPatch.Header { QuantWBits = bitpack.UnpackBits(8) }; - return itemp; - } + // Quantized word bits + if (header.QuantWBits == END_OF_PATCHES) + return header; - private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header, - int prequant, out int wbits) - { - float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int wordsize = prequant; - float oozrange = 1.0f/header.Range; - float range = (1 << prequant); - float premult = oozrange*range; - float sub = (1 << (prequant - 1)) + header.DCOffset*premult; + // DC offset + header.DCOffset = bitpack.UnpackFloat(); - header.QuantWBits = wordsize - 2; - header.QuantWBits |= (prequant - 2) << 4; + // Range + header.Range = bitpack.UnpackBits(16); - int k = 0; + // Patch IDs (10 bits) + header.PatchIDs = bitpack.UnpackBits(10); - int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ? - (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY; - yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize; + // Word bits + header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); - int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ? - (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX; - xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize; + return header; + } + */ - for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++) - { - for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++) + /* + public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) { - block[k++] = terrData[xx, yy] * premult - sub; + for (int n = 0; n < size * size; n++) + { + // ? + int temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Value or EOB + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Value + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Negative + temp = bitpack.UnpackBits((int)header.WordBits); + patches[n] = temp * -1; + } + else + { + // Positive + temp = bitpack.UnpackBits((int)header.WordBits); + patches[n] = temp; + } + } + else + { + // Set the rest to zero + // TODO: This might not be necessary + for (int o = n; o < size * size; o++) + { + patches[o] = 0; + } + break; + } + } + else + { + patches[n] = 0; + } + } } - } - - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - - int maxWbits = prequant + 5; - wbits = (prequant >> 1); - - for (int o = 0; o < Constants.TerrainPatchSize; o++) - DCTLine16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); - - return itemp; - } - - #region Initialization - - private static void BuildDequantizeTable16() + */ + #region IDCT + /* not in use + private static void IDCTColumn16(float[] linein, float[] lineout, int column) { - for (int j = 0; j < Constants.TerrainPatchSize; j++) + for (int n = 0; n < Constants.TerrainPatchSize; n++) { - for (int i = 0; i < Constants.TerrainPatchSize; i++) + float total = OO_SQRT2 * linein[column]; + + for (int u = 1; u < Constants.TerrainPatchSize; u++) { - DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j); + int usize = u * Constants.TerrainPatchSize; + total += linein[usize + column] * CosineTable16[usize + n]; } + + lineout[Constants.TerrainPatchSize * n + column] = total; } } - private static void BuildQuantizeTable16() + private static void IDCTLine16(float[] linein, float[] lineout, int line) { - const float oosob = 2.0f/Constants.TerrainPatchSize; - for (int j = 0; j < Constants.TerrainPatchSize; j++) + const float oosob = 2.0f / Constants.TerrainPatchSize; + int lineSize = line * Constants.TerrainPatchSize; + + for (int n = 0; n < Constants.TerrainPatchSize; n++) { - for (int i = 0; i < Constants.TerrainPatchSize; i++) + float total = OO_SQRT2 * linein[lineSize]; + + for (int u = 1; u < Constants.TerrainPatchSize; u++) { -// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j)); - QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j)); + total += linein[lineSize + u] * CosineTable16[u * Constants.TerrainPatchSize + n]; } + + lineout[lineSize + n] = total * oosob; } } +/* private static void SetupCosines16() { - const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize; + const float hposz = (float)Math.PI * 0.5f / Constants.TerrainPatchSize; for (int u = 0; u < Constants.TerrainPatchSize; u++) { for (int n = 0; n < Constants.TerrainPatchSize; n++) { - CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz); + CosineTable16[u * Constants.TerrainPatchSize + n] = (float)Math.Cos((2.0f * n + 1.0f) * u * hposz); } } } +*/ + //not in use, and still not fixed + /* + static void idct16x16(float[] a) + { + int j; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + float x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; + float xr, xi; - private static void BuildCopyMatrix16() - { - bool diag = false; - bool right = true; - int i = 0; - int j = 0; - int count = 0; - - while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize) - { - CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++; - - if (!diag) - { - if (right) - { - if (i < Constants.TerrainPatchSize - 1) i++; - else j++; - - right = false; - diag = true; - } - else - { - if (j < Constants.TerrainPatchSize - 1) j++; - else i++; - - right = true; - diag = true; - } - } - else - { - if (right) - { - i++; - j--; - if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false; - } - else - { - i--; - j++; - if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false; - } - } - } - } + int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; - #endregion Initialization + for (j = 0; j < fullSize; j += Constants.TerrainPatchSize) + { + x5r = C16_1R * tmp[1 + j] + C16_1I * tmp[15 + j]; + x5i = C16_1R * tmp[15 + j] - C16_1I * tmp[1 + j]; + xr = C16_7R * tmp[7 + j] + C16_7I * tmp[9 + j]; + xi = C16_7R * tmp[9 + j] - C16_7I * tmp[7 + j]; + x4r = x5r + xr; + x4i = x5i - xi; + x5r -= xr; + x5i += xi; + x7r = C16_5R * tmp[5 + j] + C16_5I * tmp[11 + j]; + x7i = C16_5R * tmp[11 + j] - C16_5I * tmp[5 + j]; + xr = C16_3R * tmp[3 + j] + C16_3I * tmp[13 + j]; + xi = C16_3R * tmp[13 + j] - C16_3I * tmp[3 + j]; + x6r = x7r + xr; + x6i = x7i - xi; + x7r -= xr; + x7i += xi; + xr = x4r - x6r; + xi = x4i - x6i; + x4r += x6r; + x4i += x6i; + x6r = W16_8R * (xi + xr); + x6i = W16_8R * (xi - xr); + xr = x5r + x7i; + xi = x5i - x7r; + x5r -= x7i; + x5i += x7r; + x7r = W16_4I * x5r + W16_4R * x5i; + x7i = W16_4I * x5i - W16_4R * x5r; + x5r = W16_4R * xr + W16_4I * xi; + x5i = W16_4R * xi - W16_4I * xr; + xr = C16_4R * tmp[4 + j] + C16_4I * tmp[12 + j]; + xi = C16_4R * tmp[12 + j] - C16_4I * tmp[4 + j]; + x2r = C16_8R * (tmp[0 + j] + tmp[8 + j]); + x3r = C16_8R * (tmp[0 + j] - tmp[8 + j]); + x0r = x2r + xr; + x1r = x3r + xi; + x2r -= xr; + x3r -= xi; + x0i = C16_2R * tmp[2 + j] + C16_2I * tmp[14 + j]; + x2i = C16_2R * tmp[14 + j] - C16_2I * tmp[2 + j]; + x1i = C16_6R * tmp[6 + j] + C16_6I * tmp[10 + j]; + x3i = C16_6R * tmp[10 + j] - C16_6I * tmp[6 + j]; + xr = x0i - x1i; + xi = x2i + x3i; + x0i += x1i; + x2i -= x3i; + x1i = W16_8R * (xi + xr); + x3i = W16_8R * (xi - xr); + xr = x0r + x0i; + xi = x0r - x0i; + tmp[0 + j] = xr + x4r; + tmp[15 + j] = xr - x4r; + tmp[8 + j] = xi + x4i; + tmp[7 + j] = xi - x4i; + xr = x1r + x1i; + xi = x1r - x1i; + tmp[2 + j] = xr + x5r; + tmp[13 + j] = xr - x5r; + tmp[10 + j] = xi + x5i; + tmp[5 + j] = xi - x5i; + xr = x2r + x2i; + xi = x2r - x2i; + tmp[4 + j] = xr + x6r; + tmp[11 + j] = xr - x6r; + tmp[12 + j] = xi + x6i; + tmp[3 + j] = xi - x6i; + xr = x3r + x3i; + xi = x3r - x3i; + tmp[6 + j] = xr + x7r; + tmp[9 + j] = xr - x7r; + tmp[14 + j] = xi + x7i; + tmp[1 + j] = xi - x7i; + } + for (j = 0; j < fullSize; j += Constants.TerrainPatchSize) + { + x5r = C16_1R * tmp[j + 1] + C16_1I * tmp[j + 15]; + x5i = C16_1R * tmp[j + 15] - C16_1I * tmp[j + 1]; + xr = C16_7R * tmp[j + 7] + C16_7I * tmp[j + 9]; + xi = C16_7R * tmp[j + 9] - C16_7I * tmp[j + 7]; + x4r = x5r + xr; + x4i = x5i - xi; + x5r -= xr; + x5i += xi; + x7r = C16_5R * tmp[j + 5] + C16_5I * tmp[j + 11]; + x7i = C16_5R * tmp[j + 11] - C16_5I * tmp[j + 5]; + xr = C16_3R * tmp[j + 3] + C16_3I * tmp[j + 13]; + xi = C16_3R * tmp[j + 13] - C16_3I * tmp[j + 3]; + x6r = x7r + xr; + x6i = x7i - xi; + x7r -= xr; + x7i += xi; + xr = x4r - x6r; + xi = x4i - x6i; + x4r += x6r; + x4i += x6i; + x6r = W16_8R * (xi + xr); + x6i = W16_8R * (xi - xr); + xr = x5r + x7i; + xi = x5i - x7r; + x5r -= x7i; + x5i += x7r; + x7r = W16_4I * x5r + W16_4R * x5i; + x7i = W16_4I * x5i - W16_4R * x5r; + x5r = W16_4R * xr + W16_4I * xi; + x5i = W16_4R * xi - W16_4I * xr; + xr = C16_4R * tmp[j + 4] + C16_4I * tmp[j + 12]; + xi = C16_4R * tmp[j + 12] - C16_4I * tmp[j + 4]; + x2r = C16_8R * (tmp[j + 0] + tmp[j + 8]); + x3r = C16_8R * (tmp[j + 0] - tmp[j + 8]); + x0r = x2r + xr; + x1r = x3r + xi; + x2r -= xr; + x3r -= xi; + x0i = C16_2R * tmp[j + 2] + C16_2I * tmp[j + 14]; + x2i = C16_2R * tmp[j + 14] - C16_2I * tmp[j + 2]; + x1i = C16_6R * tmp[j + 6] + C16_6I * tmp[j + 10]; + x3i = C16_6R * tmp[j + 10] - C16_6I * tmp[j + 6]; + xr = x0i - x1i; + xi = x2i + x3i; + x0i += x1i; + x2i -= x3i; + x1i = W16_8R * (xi + xr); + x3i = W16_8R * (xi - xr); + xr = x0r + x0i; + xi = x0r - x0i; + tmp[j + 0] = xr + x4r; + tmp[j + 15] = xr - x4r; + tmp[j + 8] = xi + x4i; + tmp[j + 7] = xi - x4i; + xr = x1r + x1i; + xi = x1r - x1i; + tmp[j + 2] = xr + x5r; + tmp[j + 13] = xr - x5r; + tmp[j + 10] = xi + x5i; + tmp[j + 5] = xi - x5i; + xr = x2r + x2i; + xi = x2r - x2i; + tmp[j + 4] = xr + x6r; + tmp[j + 11] = xr - x6r; + tmp[j + 12] = xi + x6i; + tmp[j + 3] = xi - x6i; + xr = x3r + x3i; + xi = x3r - x3i; + tmp[j + 6] = xr + x7r; + tmp[j + 9] = xr - x7r; + tmp[j + 14] = xi + x7i; + tmp[j + 1] = xi - x7i; + } + } + */ + #endregion IDCT + #endregion Decode } + } -- cgit v1.1