public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, TerrainPatch.LayerType type) { LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = (byte)type } }; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader { Stride = STRIDE, PatchSize = 16, Type = type }; // Should be enough to fit even the most poorly packed data byte[] data = new byte[patches.Length * 16 * 16 * 2]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); foreach (TerrainPatch t in patches) { CreatePatch(bitpack, t.Data, t.X, t.Y); } 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); return(layer); }
/// <summary> /// Creates a LayerData packet for compressed land data given a full /// simulator heightmap and an array of indices of patches to compress /// </summary> /// <param name="heightmap">A 256 * 256 array of floating point values /// specifying the height at each meter in the simulator</param> /// <param name="patches">Array of indexes in the 16x16 grid of patches /// for this simulator. For example if 1 and 17 are specified, patches /// x=1,y=0 and x=1,y=1 are sent</param> /// <returns></returns> public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) { LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = (byte)TerrainPatch.LayerType.Land } }; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader { Stride = STRIDE, PatchSize = 16, Type = TerrainPatch.LayerType.Land }; byte[] data = new byte[1536]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); foreach (int t in patches) { CreatePatchFromHeightmap(bitpack, heightmap, t % 16, (t - (t % 16)) / 16); } 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); return(layer); }
/// <summary> /// Creates a LayerData packet for compressed land data given a full /// simulator heightmap and an array of indices of patches to compress /// </summary> /// <param name="heightmap">A 256 * 256 array of floating point values /// specifying the height at each meter in the simulator</param> /// <param name="patches">Array of indexes in the 16x16 grid of patches /// for this simulator. For example if 1 and 17 are specified, patches /// x=1,y=0 and x=1,y=1 are sent</param> /// <returns></returns> public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) { LayerDataPacket layer = new LayerDataPacket(); layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); header.Stride = STRIDE; header.PatchSize = 16; header.Type = TerrainPatch.LayerType.Land; byte[] data = new byte[1536]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); for (int i = 0; i < patches.Length; i++) { CreatePatchFromHeightmap(bitpack, heightmap, patches[i] % 16, (patches[i] - (patches[i] % 16)) / 16); } 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); return(layer); }
public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int RegionSizeX, int RegionSizeY) { LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader {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]; 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, RegionSizeX, RegionSizeY); 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); return layer; }
private void DecompressWind(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) { int[] patches = new int[32 * 32]; // Ignore the simulator stride value group.Stride = group.PatchSize; // Each wind packet contains the wind speeds and direction for the entire simulator // stored as two float arrays. The first array is the X value of the wind speed at // each 16x16m block, second is the Y value. // wind_speed = distance(x,y to 0,0) // wind_direction = vec2(x,y) // X values TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); float[] xvalues = TerrainCompressor.DecompressPatch(patches, header, group); // Y values header = TerrainCompressor.DecodePatchHeader(bitpack); TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); float[] yvalues = TerrainCompressor.DecompressPatch(patches, header, group); if (simulator.Client.Settings.STORE_LAND_PATCHES) { for (int i = 0; i < 256; i++) { simulator.WindSpeeds[i] = new Vector2(xvalues[i], yvalues[i]); } } }
/// <summary> /// Creates a LayerData packet for compressed land data given a full /// simulator heightmap and an array of indices of patches to compress /// </summary> /// <param name="heightmap">A 256 * 256 array of floating point values /// specifying the height at each meter in the simulator</param> /// <param name="patches">Array of indexes in the 16x16 grid of patches /// for this simulator. For example if 1 and 17 are specified, patches /// x=1,y=0 and x=1,y=1 are sent</param> /// <returns></returns> public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) { LayerDataPacket layer = new LayerDataPacket(); layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); header.Stride = STRIDE; header.PatchSize = 16; header.Type = TerrainPatch.LayerType.Land; byte[] data = new byte[1536]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); for (int i = 0; i < patches.Length; i++) { CreatePatch(bitpack, heightmap, patches[i] % 16, (patches[i] - (patches[i] % 16)) / 16); } 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); return layer; }
public static LayerDataPacket CreateLandPacket(float[,] patchData, int x, int y) { LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = (byte)TerrainPatch.LayerType.Land } }; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader { Stride = STRIDE, PatchSize = 16, Type = TerrainPatch.LayerType.Land }; byte[] data = new byte[1536]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); CreatePatch(bitpack, patchData, x, y); 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); return(layer); }
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++; try { OnLandPatchReceived(new LandPatchReceivedEventArgs(simulator, x, y, group.PatchSize, heightmap)); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } if (Client.Settings.STORE_LAND_PATCHES) { TerrainPatch patch = new TerrainPatch { Data = heightmap, X = x, Y = y }; simulator.Terrain[y * 16 + x] = patch; } } }
private void LayerDataHandler(object sender, PacketReceivedEventArgs e) { LayerDataPacket layer = (LayerDataPacket)e.Packet; BitPack bitpack = new BitPack(layer.LayerData.Data, 0); TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); TerrainPatch.LayerType type = (TerrainPatch.LayerType)layer.LayerID.Type; // Stride header.Stride = bitpack.UnpackBits(16); // Patch size header.PatchSize = bitpack.UnpackBits(8); // Layer type header.Type = (TerrainPatch.LayerType)bitpack.UnpackBits(8); switch (type) { case TerrainPatch.LayerType.Land: if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES) { DecompressLand(e.Simulator, bitpack, header); } break; case TerrainPatch.LayerType.Water: Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client); break; case TerrainPatch.LayerType.Wind: DecompressWind(e.Simulator, bitpack, header); break; case TerrainPatch.LayerType.Cloud: DecompressCloud(e.Simulator, bitpack, header); break; default: Logger.Log("Unrecognized LayerData type " + type.ToString(), Helpers.LogLevel.Warning, Client); break; } }
/// <summary> /// Creates a LayerData packet for compressed land data given a full /// simulator heightmap and an array of indices of patches to compress /// </summary> /// <param name="terrData"> /// Terrain data that can result in a meter square heightmap. /// </param> /// <param name="x"> /// 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). /// </param> /// <param name="y"> /// Array of indexes in the grid of patches. /// </param> /// <param name="type"></param> /// <param name="pRegionSizeX"></param> /// <param name="pRegionSizeY"></param> /// <returns></returns> public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type) { LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; 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); for (int i = 0; i < x.Length; i++) CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]); 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); return layer; }
public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, TerrainPatch.LayerType type) { LayerDataPacket layer = new LayerDataPacket(); layer.LayerID.Type = (byte)type; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); header.Stride = STRIDE; header.PatchSize = 16; header.Type = type; // Should be enough to fit even the most poorly packed data byte[] data = new byte[patches.Length * 16 * 16 * 2]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); for (int i = 0; i < patches.Length; i++) CreatePatch(bitpack, patches[i].Data, patches[i].X, patches[i].Y); 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); return layer; }
public static LayerDataPacket CreateLandPacket(float[,] patchData, int x, int y) { LayerDataPacket layer = new LayerDataPacket(); layer.LayerID.Type = (byte)TerrainPatch.LayerType.Land; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); header.Stride = STRIDE; header.PatchSize = 16; header.Type = TerrainPatch.LayerType.Land; byte[] data = new byte[1536]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits((int)header.Type, 8); CreatePatch(bitpack, patchData, x, y); 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); return layer; }
/// <summary> /// Creates a LayerData packet for compressed land data given a full /// simulator heightmap and an array of indices of patches to compress /// </summary> /// <param name="heightmap">A 256 * 256 array of floating point values /// specifying the height at each meter in the simulator</param> /// <param name="patches">Array of indexes in the 16x16 grid of patches /// for this simulator. For example if 1 and 17 are specified, patches /// x=1,y=0 and x=1,y=1 are sent</param> /// <returns></returns> public static LayerDataPacket CreateLandPacket(short[] heightmap, int[] x, int[] y, byte type, int RegionSizeX, int RegionSizeY) { LayerDataPacket layer = new LayerDataPacket(); layer.LayerID.Type = type; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); header.Stride = STRIDE; header.PatchSize = Constants.TerrainPatchSize; byte[] data = new byte[2112]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits(type, 8); for (int i = 0; i < x.Length; i++) CreatePatchFromHeightmap(bitpack, heightmap, x[i], y[i], RegionSizeX, RegionSizeY); 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); return layer; }
private void DecompressCloud(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) { // FIXME: }
private void LayerDataHandler(Packet packet, Simulator simulator) { LayerDataPacket layer = (LayerDataPacket)packet; BitPack bitpack = new BitPack(layer.LayerData.Data, 0); TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader(); TerrainPatch.LayerType type = (TerrainPatch.LayerType)layer.LayerID.Type; // Stride header.Stride = bitpack.UnpackBits(16); // Patch size header.PatchSize = bitpack.UnpackBits(8); // Layer type header.Type = (TerrainPatch.LayerType)bitpack.UnpackBits(8); switch (type) { case TerrainPatch.LayerType.Land: if (OnLandPatch != null || Client.Settings.STORE_LAND_PATCHES) DecompressLand(simulator, bitpack, header); break; case TerrainPatch.LayerType.Water: Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client); break; case TerrainPatch.LayerType.Wind: DecompressWind(simulator, bitpack, header); break; case TerrainPatch.LayerType.Cloud: DecompressCloud(simulator, bitpack, header); break; default: Logger.Log("Unrecognized LayerData type " + type.ToString(), Helpers.LogLevel.Warning, Client); 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 / (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 LayerDataPacket CreateLandPacket(List<PatchInfo> ps, byte type) { LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = type } }; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader { Stride = STRIDE, PatchSize = Constants.TerrainPatchSize }; byte[] outdata = new byte[1500]; byte[] indata = BitConverter.GetBytes((ushort)header.Stride); if(!BitConverter.IsLittleEndian) { Array.Reverse(indata); } outdata[0] = indata[0]; outdata[1] = indata[1]; outdata[2] = (byte)header.PatchSize; outdata[3] = type; int outBitPos = 32; PatchInfo eop = new PatchInfo(); eop.PackedData = new byte[] { END_OF_PATCHES }; eop.BitLength = 8; ps.Add(eop); foreach(PatchInfo pi in ps) { int count = 0; int curBytePos = 0; int bitCount = pi.BitLength; /* this bit pack method has a slight variance allowing it to directly accept BitPacked data */ while (bitCount > 0) { count = bitCount; if (count > 8) { count = 8; } byte srcBits = pi.PackedData[curBytePos]; while (count-- > 0) { byte curBitMask = (byte)(0x80 >> (outBitPos % 8)); if ((srcBits & 0x80) != 0) { outdata[outBitPos / 8] |= curBitMask; } else { outdata[outBitPos / 8] &= (byte)~curBitMask; } ++outBitPos; srcBits <<= 1; } ++curBytePos; if (bitCount > 8) { bitCount -= 8; } else { bitCount = 0; } } } layer.LayerData.Data = new byte[(outBitPos + 7) / 8]; Buffer.BlockCopy(outdata, 0, layer.LayerData.Data, 0, (outBitPos + 7) / 8); return layer; }