/// <summary> /// /// </summary> /// <returns></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(MaxAge, 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; }
private void LayerDataHandler(Packet packet, Simulator simulator) { LayerDataPacket layer = (LayerDataPacket)packet; BitPack bitpack = new BitPack(layer.LayerData.Data, 0); GroupHeader header = new GroupHeader(); LayerType type = (LayerType)layer.LayerID.Type; // Stride header.Stride = bitpack.UnpackBits(16); // Patch size header.PatchSize = bitpack.UnpackBits(8); // Layer type header.Type = (LayerType)bitpack.UnpackBits(8); switch (type) { case LayerType.Land: if (OnLandPatch != null || Client.Settings.STORE_LAND_PATCHES) DecompressLand(simulator, bitpack, header); break; case LayerType.Water: Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client); break; case LayerType.Wind: DecompressWind(simulator, bitpack, header); break; case LayerType.Cloud: DecompressCloud(simulator, bitpack, header); break; default: Logger.Log("Unrecognized LayerData type " + type.ToString(), Helpers.LogLevel.Warning, Client); break; } }
/// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="pos"></param> public ParticleSystem(byte[] data, int pos) { // TODO: Not sure exactly how many bytes we need here, so partial // (but 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 LLVector3(x, y, z); x = pack.UnpackFixed(true, 8, 7); y = pack.UnpackFixed(true, 8, 7); z = pack.UnpackFixed(true, 8, 7); PartAcceleration = new LLVector3(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 LLColor(r, g, b, a); r = pack.UnpackByte(); g = pack.UnpackByte(); b = pack.UnpackByte(); a = pack.UnpackByte(); PartEndColor = new LLColor(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 = LLVector3.Zero; Texture = Target = LLUUID.Zero; PartDataFlags = ParticleDataFlags.None; PartMaxAge = 0.0f; PartStartColor = PartEndColor = LLColor.Black; PartStartScaleX = PartStartScaleY = PartEndScaleX = PartEndScaleY = 0.0f; } }
private void DecompressLand(Simulator simulator, BitPack bitpack, GroupHeader group) { int x; int y; int[] patches = new int[32 * 32]; int count = 0; while (true) { PatchHeader header = DecodePatchHeader(bitpack); if (header.QuantWBits == END_OF_PATCHES) break; x = header.PatchIDs >> 5; y = header.PatchIDs & 0x1F; if (x >= PATCHES_PER_EDGE || y >= PATCHES_PER_EDGE) { Logger.Log("Invalid LayerData land packet, x = " + x + ", y = " + y + ", dc_offset = " + header.DCOffset + ", range = " + header.Range + ", quant_wbits = " + header.QuantWBits + ", patchids = " + header.PatchIDs + ", count = " + count, Helpers.LogLevel.Warning, Client); return; } // Decode this patch DecodePatch(patches, bitpack, header, group.PatchSize); // Decompress this patch float[] heightmap = 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 Patch[16 * 16]); SimPatches[simulator.Handle][y * 16 + x] = new Patch(); SimPatches[simulator.Handle][y * 16 + x].Heightmap = heightmap; } } } }
private void DecompressCloud(Simulator simulator, BitPack bitpack, GroupHeader group) { ; }
private void DecodePatch(int[] patches, BitPack bitpack, PatchHeader header, int size) { int temp; for (int n = 0; n < size * size; n++) { // ? 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 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, Client); 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 PatchHeader DecodePatchHeader(BitPack bitpack) { PatchHeader header = new PatchHeader(); // Quantized word bits header.QuantWBits = bitpack.UnpackBits(8); 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> /// /// </summary> /// <param name="output"></param> /// <param name="header"></param> /// <param name="patch"></param> /// <returns>wbits</returns> private int EncodePatchHeader(BitPack output, PatchHeader 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, Client); } 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; }
/// <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 void CreatePatch(BitPack output, float[] heightmap, int x, int y) { if (heightmap.Length != 256 * 256) { Logger.Log("Invalid heightmap value of " + heightmap.Length + " passed to CreatePatch()", Helpers.LogLevel.Error, Client); return; } if (x < 0 || x > 15 || y < 0 || y > 15) { Logger.Log("Invalid x or y patch offset passed to CreatePatch(), x=" + x + ", y=" + y, Helpers.LogLevel.Error, Client); return; } PatchHeader header = PrescanPatch(heightmap, x, y); header.QuantWBits = 136; header.PatchIDs = (y & 0x1F); header.PatchIDs += (x << 5); // TODO: What is prequant? int[] patch = CompressPatch(heightmap, x, y, header, 10); int wbits = EncodePatchHeader(output, header, patch); // TODO: What is postquant? EncodePatch(output, patch, 0, wbits); }
/// <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 LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) { LayerDataPacket layer = new LayerDataPacket(); layer.LayerID.Type = (byte)LayerType.Land; GroupHeader header = new GroupHeader(); header.Stride = STRIDE; header.PatchSize = 16; header.Type = 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 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"); }
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"); }
/// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="pos"></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 LLVector3(x, y, z); x = pack.UnpackFixed(true, 8, 7); y = pack.UnpackFixed(true, 8, 7); z = pack.UnpackFixed(true, 8, 7); PartAcceleration = new LLVector3(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 LLColor(r, g, b, a); r = pack.UnpackByte(); g = pack.UnpackByte(); b = pack.UnpackByte(); a = pack.UnpackByte(); PartEndColor = new LLColor(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 = LLVector3.Zero; Texture = Target = LLUUID.Zero; PartDataFlags = ParticleDataFlags.None; PartMaxAge = 0.0f; PartStartColor = PartEndColor = LLColor.Black; PartStartScaleX = PartStartScaleY = PartEndScaleX = PartEndScaleY = 0.0f; } }