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(); patch.Data = heightmap; patch.X = x; patch.Y = y; simulator.Terrain[y * 16 + x] = patch; } } }
/// <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 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; }
public static int GetParcelArea(SceneParcel parcel, out Vector3 aabbMin, out Vector3 aabbMax) { int minX = 64; int minY = 64; int maxX = 0; int maxY = 0; int area = 0; System.Diagnostics.Debug.Assert(parcel.Bitmap != null); System.Diagnostics.Debug.Assert(parcel.Bitmap.Length == 512); BitPack bitmap = new BitPack(parcel.Bitmap, 0); for (int y = 0; y < 64; y++) { for (int x = 0; x < 64; x++) { if (bitmap.UnpackBits(1) != 0) { int x4 = x * 4; int y4 = y * 4; if (minX > x4) minX = x4; if (minY > y4) minY = y4; if (maxX < x4) maxX = x4; if (maxX < y4) maxY = y4; area += 16; } } } aabbMin = new Vector3(minX, minY, 0f); aabbMax = new Vector3(maxX, maxY, 0f); return area; }
public void BitUnpacking() { byte[] data = new byte[] { 0x80, 0x00, 0x0F, 0x50, 0x83, 0x7D }; BitPack bitpacker = new BitPack(data, 0); int b = bitpacker.UnpackBits(1); Assert.IsTrue(b == 1, "Unpacked " + b + " instead of 1"); b = bitpacker.UnpackBits(1); Assert.IsTrue(b == 0, "Unpacked " + b + " instead of 0"); bitpacker = new BitPack(data, 2); b = bitpacker.UnpackBits(4); Assert.IsTrue(b == 0, "Unpacked " + b + " instead of 0"); b = bitpacker.UnpackBits(8); Assert.IsTrue(b == 0xF5, "Unpacked " + b + " instead of 0xF5"); b = bitpacker.UnpackBits(4); Assert.IsTrue(b == 0, "Unpacked " + b + " instead of 0"); b = bitpacker.UnpackBits(10); Assert.IsTrue(b == 0x0183, "Unpacked " + b + " instead of 0x0183"); }
public void BitPacking() { byte[] packedBytes = new byte[12]; BitPack bitpacker = new BitPack(packedBytes, 0); bitpacker.PackBits(0x0ABBCCDD, 32); bitpacker.PackBits(25, 5); bitpacker.PackFloat(123.321f); bitpacker.PackBits(1000, 16); bitpacker = new BitPack(packedBytes, 0); int b = bitpacker.UnpackBits(32); Assert.IsTrue(b == 0x0ABBCCDD, "Unpacked " + b + " instead of 2864434397"); b = bitpacker.UnpackBits(5); Assert.IsTrue(b == 25, "Unpacked " + b + " instead of 25"); float f = bitpacker.UnpackFloat(); Assert.IsTrue(f == 123.321f, "Unpacked " + f + " instead of 123.321"); b = bitpacker.UnpackBits(16); Assert.IsTrue(b == 1000, "Unpacked " + b + " instead of 1000"); packedBytes = new byte[1]; bitpacker = new BitPack(packedBytes, 0); bitpacker.PackBit(true); bitpacker = new BitPack(packedBytes, 0); b = bitpacker.UnpackBits(1); Assert.IsTrue(b == 1, "Unpacked " + b + " instead of 1"); packedBytes = new byte[1] { Byte.MaxValue }; bitpacker = new BitPack(packedBytes, 0); bitpacker.PackBit(false); bitpacker = new BitPack(packedBytes, 0); b = bitpacker.UnpackBits(1); Assert.IsTrue(b == 0, "Unpacked " + b + " instead of 0"); }
private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) { int temp; bool eob; if (postquant > 16 * 16 || postquant < 0) { Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); return; } if (postquant != 0) patch[16 * 16 - postquant] = 0; for (int i = 0; i < 16 * 16; i++) { eob = false; temp = patch[i]; if (temp == 0) { eob = true; for (int j = i; j < 16 * 16 - postquant; j++) { if (patch[j] != 0) { eob = false; break; } } if (eob) { output.PackBits(ZERO_EOB, 2); return; } else { output.PackBits(ZERO_CODE, 1); } } else { if (temp < 0) { temp *= -1; if (temp > (1 << wbits)) temp = (1 << wbits); output.PackBits(NEGATIVE_VALUE, 3); output.PackBits(temp, wbits); } else { if (temp > (1 << wbits)) temp = (1 << wbits); output.PackBits(POSITIVE_VALUE, 3); output.PackBits(temp, wbits); } } } }
private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) { int maxwbitssize = (1 << wbits) - 1; 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 (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0; for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) { int temp = patch[i]; if (temp == 0) { bool eob = true; for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++) { if (patch[j] != 0) { eob = false; break; } } if (eob) { output.PackBits(ZERO_EOB, 2); return; } output.PackBits(ZERO_CODE, 1); } else { if (temp < 0) { temp *= -1; if (temp > maxwbitssize) temp = maxwbitssize; output.PackBits(NEGATIVE_VALUE, 3); output.PackBits(temp, wbits); } else { if (temp > maxwbitssize) temp = maxwbitssize; output.PackBits(POSITIVE_VALUE, 3); output.PackBits(temp, wbits); } } } }
private void DecompressCloud(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) { // FIXME: }
/// <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. Presumed to be an sizeX*sizeY array. /// </param> /// <param name="patchX"> /// X offset of the patch to create. /// </param> /// <param name="patchY"> /// Y offset of the patch to create. /// </param> /// <param name="pRegionSizeX"></param> /// <param name="pRegionSizeY"></param> public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY) { TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY); header.QuantWBits = 136; // 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); } else { header.PatchIDs = (patchY & 0x1F); header.PatchIDs += (patchX << 5); } // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}", // LogHeader, patchX, patchY, header.DCOffset, header.Range); // 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); }
private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX, uint pRegionSizeY, 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; 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) output.PackBits(header.PatchIDs, 32); else output.PackBits(header.PatchIDs, 10); return wbits; }
private void UpdateParcelOverlay(SceneParcel parcel) { BitPack bitmap = new BitPack(parcel.Bitmap, 0); for (int y = 0; y < 64; y++) { for (int x = 0; x < 64; x++) { if (bitmap.UnpackBits(1) != 0) m_parcelOverlay[y * 64 + x] = parcel.LocalID; } } }
/// <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 byte[] GetCompressedPatch(int patchx, int patchy, out int bitlength, uint lastSerialNo, out uint serialNo) { lock(m_PackedSerialLock) { #if UPDATE_TERRAIN_ONLY_WHEN_NECESSARY if(m_PackedTerrainPatches[patchx, patchy].Serial == lastSerialNo && 0 != lastSerialNo) { /* signal no change via null */ serialNo = lastSerialNo; bitlength = 0; return null; } if(m_PackedTerrainPatches[patchx, patchy].Serial != m_TerrainPatchSerial[patchx, patchy]) #endif { m_PackedTerrainPatches[patchx, patchy].Serial = m_TerrainPatchSerial[patchx, patchy]; m_PackedTerrainPatches[patchx, patchy].CompressedPatch = new byte[651]; /* maximum length of a single compressed patch */ BitPack bitpack = new BitPack(m_PackedTerrainPatches[patchx, patchy].CompressedPatch, 0); OpenSimTerrainCompressor.CreatePatchFromHeightmap(bitpack, this, patchx, patchy); m_PackedTerrainPatches[patchx, patchy].BitLength = 8 * bitpack.BytePos + bitpack.BitPos; if(0 == bitpack.BitPos) { m_PackedTerrainPatches[patchx, patchy].BitLength += 8; } } bitlength = m_PackedTerrainPatches[patchx, patchy].BitLength; byte[] copy = new byte[m_PackedTerrainPatches[patchx, patchy].CompressedPatch.Length]; Buffer.BlockCopy(m_PackedTerrainPatches[patchx, patchy].CompressedPatch, 0, copy, 0, copy.Length); serialNo = m_PackedTerrainPatches[patchx, patchy].Serial; return copy; } }
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); ulong handle = simulator.Handle; Vector2[] windSpeeds; lock (WindSpeeds.Dictionary) { if (!WindSpeeds.TryGetValue(handle,out windSpeeds)) { windSpeeds = WindSpeeds[handle] = new Vector2[256]; } } for (int i = 0; i < 256; i++) windSpeeds[i] = new Vector2(xvalues[i], yvalues[i]); }
private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, int RegionSizeX, int RegionSizeY, int wbits) { // better check if (wbits > 17) wbits = 16; else if (wbits < 3) wbits = 3; header.QuantWBits &= 0xf0; header.QuantWBits |= (wbits - 2); output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); if (RegionSizeX > Constants.RegionSize || RegionSizeY > Constants.RegionSize) output.PackBits(header.PatchIDs, 32); else output.PackBits(header.PatchIDs, 10); return wbits; }
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> /// 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> /// <param name="RegionSizeX"></param> /// <param name="RegionSizeY"></param> public static void CreatePatchFromHeightmap(BitPack output, short[] heightmap, int x, int y, int RegionSizeX, int RegionSizeY) { TerrainPatch.Header header = PrescanPatch(heightmap, x, y, RegionSizeX, RegionSizeY); header.QuantWBits = 136; if (RegionSizeX > Constants.RegionSize || RegionSizeY > Constants.RegionSize) { header.PatchIDs = (y & 0xFFFF); header.PatchIDs += (x << 16); } else { header.PatchIDs = (y & 0x1F); header.PatchIDs += (x << 5); } // NOTE: No idea what prequant and postquant should be or what they do int wbits; int[] patch = CompressPatch(heightmap, x, y, header, 10, RegionSizeX, RegionSizeY, out wbits); wbits = EncodePatchHeader(output, header, patch, RegionSizeX, RegionSizeY, wbits); EncodePatch(output, patch, 0, wbits); }
/// <summary> /// Generate byte[] array from particle data /// </summary> /// <returns>Byte array</returns> public byte[] GetBytes() { int size = LegacyDataBlockSize; if (!IsLegacyCompatible()) { size += 8; // two new ints for size } if (HasGlow()) { size += 2; // two bytes for start and end glow } if (HasBlendFunc()) { size += 2; // two bytes for start end end blend function } byte[] bytes = new byte[size]; BitPack pack = new BitPack(bytes, 0); if (IsLegacyCompatible()) { PackSystemBytes(ref pack); PackLegacyData(ref pack); } else { if (HasGlow()) { PartDataFlags |= ParticleDataFlags.DataGlow; } if (HasBlendFunc()) { PartDataFlags |= ParticleDataFlags.DataBlend; } pack.PackBitsFromUInt((uint)SysDataSize); PackSystemBytes(ref pack); int partSize = PartDataSize; if (HasGlow()) { partSize += 2; // two bytes for start and end glow } if (HasBlendFunc()) { partSize += 2; // two bytes for start end end blend function } pack.PackBitsFromUInt((uint)partSize); PackLegacyData(ref pack); if (HasGlow()) { pack.PackBitsFromByte((byte)(PartStartGlow * 255f)); pack.PackBitsFromByte((byte)(PartEndGlow * 255f)); } if (HasBlendFunc()) { pack.PackBitsFromByte(BlendFuncSource); pack.PackBitsFromByte(BlendFuncDest); } } return(bytes); }
/// <summary> /// Decodes a byte[] array into a ParticleSystem Object /// </summary> /// <param name="data">ParticleSystem object</param> /// <param name="pos">Start position for BitPacker</param> public ParticleSystem(byte[] data, int pos) { // TODO: Not sure exactly how many bytes we need here, so partial // (truncated) data will cause an exception to be thrown if (data.Length > 0) { BitPack pack = new BitPack(data, pos); CRC = pack.UnpackUBits(32); PartFlags = pack.UnpackUBits(32); Pattern = (SourcePattern)pack.UnpackByte(); MaxAge = pack.UnpackFixed(false, 8, 8); StartAge = pack.UnpackFixed(false, 8, 8); InnerAngle = pack.UnpackFixed(false, 3, 5); OuterAngle = pack.UnpackFixed(false, 3, 5); BurstRate = pack.UnpackFixed(false, 8, 8); BurstRadius = pack.UnpackFixed(false, 8, 8); BurstSpeedMin = pack.UnpackFixed(false, 8, 8); BurstSpeedMax = pack.UnpackFixed(false, 8, 8); BurstPartCount = pack.UnpackByte(); float x = pack.UnpackFixed(true, 8, 7); float y = pack.UnpackFixed(true, 8, 7); float z = pack.UnpackFixed(true, 8, 7); AngularVelocity = new Vector3(x, y, z); x = pack.UnpackFixed(true, 8, 7); y = pack.UnpackFixed(true, 8, 7); z = pack.UnpackFixed(true, 8, 7); PartAcceleration = new Vector3(x, y, z); Texture = pack.UnpackUUID(); Target = pack.UnpackUUID(); PartDataFlags = (ParticleDataFlags)pack.UnpackUBits(32); PartMaxAge = pack.UnpackFixed(false, 8, 8); byte r = pack.UnpackByte(); byte g = pack.UnpackByte(); byte b = pack.UnpackByte(); byte a = pack.UnpackByte(); PartStartColor = new Color4(r, g, b, a); r = pack.UnpackByte(); g = pack.UnpackByte(); b = pack.UnpackByte(); a = pack.UnpackByte(); PartEndColor = new Color4(r, g, b, a); PartStartScaleX = pack.UnpackFixed(false, 3, 5); PartStartScaleY = pack.UnpackFixed(false, 3, 5); PartEndScaleX = pack.UnpackFixed(false, 3, 5); PartEndScaleY = pack.UnpackFixed(false, 3, 5); } else { CRC = PartFlags = 0; Pattern = SourcePattern.None; MaxAge = StartAge = InnerAngle = OuterAngle = BurstRate = BurstRadius = BurstSpeedMin = BurstSpeedMax = 0.0f; BurstPartCount = 0; AngularVelocity = PartAcceleration = Vector3.Zero; Texture = Target = UUID.Zero; PartDataFlags = ParticleDataFlags.None; PartMaxAge = 0.0f; PartStartColor = PartEndColor = Color4.Black; PartStartScaleX = PartStartScaleY = PartEndScaleX = PartEndScaleY = 0.0f; } }
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 void SplitParcel(SceneParcel parcel, int startX, int endX, int startY, int endY) { SceneParcel newParcel = new SceneParcel(parcel); newParcel.ID = UUID.Random(); newParcel.LocalID = System.Threading.Interlocked.Increment(ref m_currentParcelID); newParcel.ClaimDate = DateTime.UtcNow; newParcel.Dwell = 0f; m_parcels.Add(newParcel.ID, newParcel.LocalID, newParcel); // Update parcel bitmaps BitPack origParcelBitmap = new BitPack(parcel.Bitmap, 0); BitPack parcelBitmap = new BitPack(new byte[512], 0); BitPack newParcelBitmap = new BitPack(newParcel.Bitmap, 0); for (int y = 0; y < 64; y++) { for (int x = 0; x < 64; x++) { bool origParcelBit = (origParcelBitmap.UnpackBits(1) != 0); if (x >= startX && x <= endX && y >= startY && y <= endY) { // Inside the new parcel parcelBitmap.PackBit(false); newParcelBitmap.PackBit(true); m_parcelOverlay[y * 64 + x] = newParcel.LocalID; } else { // Not inside the new parcel parcelBitmap.PackBit(origParcelBit); newParcelBitmap.PackBit(false); } } } // Update parcel landing info SceneParcel landingParcel; if (TryGetParcel(newParcel.LandingLocation, out landingParcel) && landingParcel == parcel) { newParcel.Landing = LandingType.None; newParcel.LandingLocation = Vector3.Zero; } else { parcel.Landing = LandingType.None; parcel.LandingLocation = Vector3.Zero; } // Update max prim counts Vector3 aabbMin, aabbMax; int area = GetParcelArea(parcel, out aabbMin, out aabbMax); parcel.MaxPrims = (int)Math.Round((float)area * m_primsPerSquareMeter); area = GetParcelArea(newParcel, out aabbMin, out aabbMax); newParcel.MaxPrims = (int)Math.Round((float)area * m_primsPerSquareMeter); Serialize(); }
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; } }
/// <summary> /// Decodes a byte[] array into a ParticleSystem Object /// </summary> /// <param name="data">ParticleSystem object</param> /// <param name="pos">Start position for BitPacker</param> public ParticleSystem(byte[] data, int pos) { PartStartGlow = 0f; PartEndGlow = 0f; BlendFuncSource = (byte)BlendFunc.SourceAlpha; BlendFuncDest = (byte)BlendFunc.OneMinusSourceAlpha; CRC = PartFlags = 0; Pattern = SourcePattern.None; MaxAge = StartAge = InnerAngle = OuterAngle = BurstRate = BurstRadius = BurstSpeedMin = BurstSpeedMax = 0.0f; BurstPartCount = 0; AngularVelocity = PartAcceleration = Vector3.Zero; Texture = Target = UUID.Zero; PartDataFlags = ParticleDataFlags.None; PartMaxAge = 0.0f; PartStartColor = PartEndColor = Color4.Black; PartStartScaleX = PartStartScaleY = PartEndScaleX = PartEndScaleY = 0.0f; int size = data.Length - pos; BitPack pack = new BitPack(data, pos); if (size == LegacyDataBlockSize) { UnpackSystem(ref pack); UnpackLegacyData(ref pack); } else if (size > LegacyDataBlockSize && size <= MaxDataBlockSize) { int sysSize = pack.UnpackInt(); if (sysSize != SysDataSize) { return; // unkown particle system data size } UnpackSystem(ref pack); int dataSize = pack.UnpackInt(); UnpackLegacyData(ref pack); if ((PartDataFlags & ParticleDataFlags.DataGlow) == ParticleDataFlags.DataGlow) { if (pack.Data.Length - pack.BytePos < 2) { return; } uint glow = pack.UnpackByte(); PartStartGlow = glow / 255f; glow = pack.UnpackByte(); PartEndGlow = glow / 255f; } if ((PartDataFlags & ParticleDataFlags.DataBlend) == ParticleDataFlags.DataBlend) { if (pack.Data.Length - pack.BytePos < 2) { return; } BlendFuncSource = pack.UnpackByte(); BlendFuncDest = pack.UnpackByte(); } } }
// Unused: left for historical reference. public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY) { TerrainPatch.Header header = PrescanPatch(patchData); header.QuantWBits = 136; if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) { header.PatchIDs = (y & 0xFFFF); header.PatchIDs += (x << 16); } else { header.PatchIDs = (y & 0x1F); header.PatchIDs += (x << 5); } // NOTE: No idea what prequant and postquant should be or what they do 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); }
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; } } } }
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; }
/// <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); }
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) { // 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; } } }
private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch) { int temp; int wbits = (header.QuantWBits & 0x0f) + 2; uint maxWbits = (uint)wbits + 5; uint minWbits = ((uint)wbits >> 1); wbits = (int)minWbits; for (int i = 0; i < patch.Length; i++) { temp = patch[i]; if (temp != 0) { // Get the absolute value if (temp < 0) temp *= -1; for (int j = (int)maxWbits; j > (int)minWbits; j--) { if ((temp & (1 << j)) != 0) { if (j > wbits) wbits = j; break; } } } } wbits += 1; header.QuantWBits &= 0xf0; if (wbits > 17 || wbits < 2) { Logger.Log("Bits needed per word in EncodePatchHeader() are outside the allowed range", Helpers.LogLevel.Error); } header.QuantWBits |= (wbits - 2); output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); output.PackBits(header.PatchIDs, 10); return wbits; }
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; }
private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) { int temp; bool eob; if (postquant > 16 * 16 || postquant < 0) { Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); return; } if (postquant != 0) { patch[16 * 16 - postquant] = 0; } for (int i = 0; i < 16 * 16; i++) { eob = false; temp = patch[i]; if (temp == 0) { eob = true; for (int j = i; j < 16 * 16 - postquant; j++) { if (patch[j] != 0) { eob = false; break; } } if (eob) { output.PackBits(ZERO_EOB, 2); return; } else { output.PackBits(ZERO_CODE, 1); } } else { if (temp < 0) { temp *= -1; if (temp > (1 << wbits)) { temp = (1 << wbits); } output.PackBits(NEGATIVE_VALUE, 3); output.PackBits(temp, wbits); } else { if (temp > (1 << wbits)) { temp = (1 << wbits); } output.PackBits(POSITIVE_VALUE, 3); output.PackBits(temp, wbits); } } } }
/// <summary> /// Generate byte[] array from particle data /// </summary> /// <returns>Byte array</returns> public byte[] GetBytes() { byte[] bytes = new byte[86]; BitPack pack = new BitPack(bytes, 0); pack.PackBits(CRC, 32); pack.PackBits((uint)PartFlags, 32); pack.PackBits((uint)Pattern, 8); pack.PackFixed(MaxAge, false, 8, 8); pack.PackFixed(StartAge, false, 8, 8); pack.PackFixed(InnerAngle, false, 3, 5); pack.PackFixed(OuterAngle, false, 3, 5); pack.PackFixed(BurstRate, false, 8, 8); pack.PackFixed(BurstRadius, false, 8, 8); pack.PackFixed(BurstSpeedMin, false, 8, 8); pack.PackFixed(BurstSpeedMax, false, 8, 8); pack.PackBits(BurstPartCount, 8); pack.PackFixed(AngularVelocity.X, true, 8, 7); pack.PackFixed(AngularVelocity.Y, true, 8, 7); pack.PackFixed(AngularVelocity.Z, true, 8, 7); pack.PackFixed(PartAcceleration.X, true, 8, 7); pack.PackFixed(PartAcceleration.Y, true, 8, 7); pack.PackFixed(PartAcceleration.Z, true, 8, 7); pack.PackUUID(Texture); pack.PackUUID(Target); pack.PackBits((uint)PartDataFlags, 32); pack.PackFixed(PartMaxAge, false, 8, 8); pack.PackColor(PartStartColor); pack.PackColor(PartEndColor); pack.PackFixed(PartStartScaleX, false, 3, 5); pack.PackFixed(PartStartScaleY, false, 3, 5); pack.PackFixed(PartEndScaleX, false, 3, 5); pack.PackFixed(PartEndScaleY, false, 3, 5); return bytes; }
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); }