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 / (float)quantize; float mult = ooq * (float)header.Range; float addval = mult * (float)(1 << (prequant - 1)) + header.DCOffset; if (group.PatchSize == 16) { for (int n = 0; n < 16 * 16; n++) { block[n] = patches[CopyMatrix16[n]] * DequantizeTable16[n]; } float[] ftemp = new float[16 * 16]; for (int o = 0; o < 16; o++) { IDCTColumn16(block, ftemp, o); } for (int o = 0; o < 16; o++) { IDCTLine16(ftemp, block, o); } } else { for (int n = 0; n < 32 * 32; n++) { block[n] = patches[CopyMatrix32[n]] * DequantizeTable32[n]; } Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error); } for (int j = 0; j < block.Length; j++) { output[j] = block[j] * mult + addval; } return(output); }
public static void CreatePatch(BitPack output, float[] patchData, int x, int y) { if (patchData.Length != 16 * 16) { throw new ArgumentException("Patch data must be a 16x16 array"); } TerrainPatch.Header header = PrescanPatch(patchData); header.QuantWBits = 136; header.PatchIDs = (y & 0x1F); header.PatchIDs += (x << 5); // NOTE: No idea what prequant and postquant should be or what they do int[] patch = CompressPatch(patchData, header, 10); int wbits = EncodePatchHeader(output, header, patch); EncodePatch(output, patch, 0, wbits); }
public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) { for (int n = 0; n < size * size; n++) { // ? var 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; } } }
/// <summary> /// Add a patch of terrain to a BitPacker /// </summary> /// <param name="output">BitPacker to write the patch to</param> /// <param name="heightmap">Heightmap of the simulator, must be a 256 * /// 256 float array</param> /// <param name="x">X offset of the patch to create, valid values are /// from 0 to 15</param> /// <param name="y">Y offset of the patch to create, valid values are /// from 0 to 15</param> public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y) { if (heightmap.Length != 256 * 256) { throw new ArgumentException("Heightmap data must be 256x256"); } if (x < 0 || x > 15 || y < 0 || y > 15) { throw new ArgumentException("X and Y patch offsets must be from 0 to 15"); } TerrainPatch.Header header = PrescanPatch(heightmap, x, y); header.QuantWBits = 136; header.PatchIDs = (y & 0x1F); header.PatchIDs += (x << 5); // NOTE: No idea what prequant and postquant should be or what they do int[] patch = CompressPatch(heightmap, x, y, header, 10); int wbits = EncodePatchHeader(output, header, patch); EncodePatch(output, patch, 0, wbits); }
private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant) { float[] block = new float[16 * 16]; int wordsize = prequant; float oozrange = 1.0f / (float)header.Range; float range = (float)(1 << prequant); float premult = oozrange * range; float sub = (float)(1 << (prequant - 1)) + header.DCOffset * premult; header.QuantWBits = wordsize - 2; header.QuantWBits |= (prequant - 2) << 4; int k = 0; for (int j = 0; j < 16; j++) { for (int i = 0; i < 16; i++) { block[k++] = patchData[j, i] * premult - sub; } } float[] ftemp = new float[16 * 16]; int[] itemp = new int[16 * 16]; for (int o = 0; o < 16; o++) { DCTLine16(block, ftemp, o); } for (int o = 0; o < 16; o++) { DCTColumn16(ftemp, itemp, o); } return(itemp); }
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); return header; }
// 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) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++) { for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++) { float val = terrData[i, j]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return header; }
private static TerrainPatch.Header PrescanPatch(float[] patch) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) { float val = patch[i]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } header.DCOffset = zmin; header.Range = (int) ((zmax - zmin) + 1.0f); return header; }
private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY, int RegionSizeX, int RegionSizeY) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = -32767; float zmin = 32767; for (int j = patchY * 16; j < (patchY + 1) * 16; j++) { for (int i = patchX * 16; i < (patchX + 1) * 16; i++) { float val = heightmap[j * RegionSizeX + i]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = (zmin); header.Range = (int)(((zmax - zmin)) + 1.0f); return header; }
private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int j = patchY * 16; j < (patchY + 1) * 16; j++) { for (int i = patchX * 16; i < (patchX + 1) * 16; i++) { float val = heightmap[j * 256 + i]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return header; }
private static TerrainPatch.Header PrescanPatch(float[,] patch) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = -99999999.0f; float zmin = 99999999.0f; for (int j = 0; j < 16; j++) { for (int i = 0; i < 16; i++) { float val = patch[j, i]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return header; }
private static TerrainPatch.Header PrescanPatch(short[] heightmap, int patchX, int patchY, int RegionSizeX, int RegionSizeY) { TerrainPatch.Header header = new TerrainPatch.Header(); short zmax = -32767; short zmin = 32767; const float iscale = 1.0f/Constants.TerrainCompression; for (int j = patchY*16; j < (patchY + 1)*16; j++) { for (int i = patchX*16; i < (patchX + 1)*16; i++) { short val = heightmap[j*RegionSizeX + i]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = (zmin)*iscale; header.Range = (int) (((zmax - zmin))*iscale + 1.0f); return header; }
// 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, out float frange) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = float.MinValue; float zmin = float.MaxValue; int startx = patchX * Constants.TerrainPatchSize; int starty = patchY * Constants.TerrainPatchSize; for (int j = starty; j < starty + Constants.TerrainPatchSize; j++) { for (int i = startx; i < startx + Constants.TerrainPatchSize; i++) { float val = terrData[i, j]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = zmin; frange = ((zmax - zmin) + 1.0f); header.Range = (int)frange; return header; }
private void DecompressLand(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) { int x; int y; int[] patches = new int[32 * 32]; int count = 0; while (true) { TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); if (header.QuantWBits == TerrainCompressor.END_OF_PATCHES) { break; } x = header.X; y = header.Y; if (x >= TerrainCompressor.PATCHES_PER_EDGE || y >= TerrainCompressor.PATCHES_PER_EDGE) { Logger.Log(String.Format( "Invalid LayerData land packet, x={0}, y={1}, dc_offset={2}, range={3}, quant_wbits={4}, patchids={5}, count={6}", x, y, header.DCOffset, header.Range, header.QuantWBits, header.PatchIDs, count), Helpers.LogLevel.Warning, Client); return; } // Decode this patch TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); // Decompress this patch float[] heightmap = TerrainCompressor.DecompressPatch(patches, header, group); count++; if (OnLandPatch != null) { try { OnLandPatch(simulator, x, y, group.PatchSize, heightmap); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } if (Client.Settings.STORE_LAND_PATCHES) { lock (SimPatches) { if (!SimPatches.ContainsKey(simulator.Handle)) { SimPatches.Add(simulator.Handle, new TerrainPatch[16 * 16]); } TerrainPatch patch = new TerrainPatch(); patch.Data = heightmap; patch.X = x; patch.Y = y; SimPatches[simulator.Handle][y * 16 + x] = patch; } } } }
private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY, int RegionSizeX, int RegionSizeY) { TerrainPatch.Header header = new TerrainPatch.Header(); float zmax = -99999999.0f; float zmin = 99999999.0f; // int sqrt = (int)Math.Sqrt(heightmap.Length); for (int j = patchY * Constants.TerrainPatchSize; j < ((patchY >= (RegionSizeY / Constants.TerrainPatchSize) ? (RegionSizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY) + 1) * Constants.TerrainPatchSize; j++) { for (int i = patchX * Constants.TerrainPatchSize; i < ((patchX >= (RegionSizeX / Constants.TerrainPatchSize) ? (RegionSizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX) + 1) * Constants.TerrainPatchSize; i++) { float val = heightmap[j * RegionSizeX + i]; if (val > zmax) zmax = val; if (val < zmin) zmin = val; } } header.DCOffset = zmin; header.Range = (int)((zmax - zmin) + 1.0f); return header; }