Add code to terrain packet compression/decompression to handle LayerType.LandExtended.
Passed flag "largeRegion" around which properly parses ParcelIDs in layer packet headers. Some notes on functions that won't work for varregions (like GlobalPosToRegionHandle).
This commit is contained in:
@@ -206,6 +206,7 @@ namespace OpenMetaverse.Assets
|
||||
|
||||
private static bool LoadTerrain(string filePath, byte[] data, TerrainLoadedCallback terrainCallback, long bytesRead, long totalBytes)
|
||||
{
|
||||
// TODO: This needs to be re-written to read data from a saved varregion (sizeX != 256)
|
||||
float[,] terrain = new float[256, 256];
|
||||
bool loaded = false;
|
||||
|
||||
@@ -350,10 +351,10 @@ namespace OpenMetaverse.Assets
|
||||
BinaryWriter bs = new BinaryWriter(s);
|
||||
|
||||
int y;
|
||||
for (y = 0; y < 256; y++)
|
||||
for (y = 0; y < sim.SizeY; y++)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < 256; x++)
|
||||
for (x = 0; x < sim.SizeX; x++)
|
||||
{
|
||||
float height;
|
||||
sim.TerrainHeightAtPoint(x, y, out height);
|
||||
|
||||
@@ -158,14 +158,15 @@ namespace OpenMetaverse
|
||||
public uint GlobalY;
|
||||
|
||||
/// <summary>Get the Local X position of the item</summary>
|
||||
public uint LocalX { get { return GlobalX % 256; } }
|
||||
public uint LocalX { get { return GlobalX % Simulator.DefaultRegionSizeX; } }
|
||||
/// <summary>Get the Local Y position of the item</summary>
|
||||
public uint LocalY { get { return GlobalY % 256; } }
|
||||
public uint LocalY { get { return GlobalY % Simulator.DefaultRegionSizeY; } }
|
||||
|
||||
/// <summary>Get the Handle of the region</summary>
|
||||
public ulong RegionHandle
|
||||
{
|
||||
get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % 256)), (uint)(GlobalY - (GlobalY % 256))); }
|
||||
get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % Simulator.DefaultRegionSizeX)),
|
||||
(uint)(GlobalY - (GlobalY % Simulator.DefaultRegionSizeY))); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,6 +149,11 @@ namespace OpenMetaverse
|
||||
/// Given an X/Y location in absolute (grid-relative) terms, a region
|
||||
/// handle is returned along with the local X/Y location in that region
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: this does not work for varregions -- the region handle is correct but
|
||||
/// the local X,Y are wrong. TODO: create new function
|
||||
/// that takes a reference to the region and thus can calculate region local address.
|
||||
/// </remarks>
|
||||
/// <param name="globalX">The absolute X location, a number such as
|
||||
/// 255360.35</param>
|
||||
/// <param name="globalY">The absolute Y location, a number such as
|
||||
@@ -160,8 +165,8 @@ namespace OpenMetaverse
|
||||
/// <returns>A 64-bit region handle that can be used to teleport to</returns>
|
||||
public static ulong GlobalPosToRegionHandle(float globalX, float globalY, out float localX, out float localY)
|
||||
{
|
||||
uint x = ((uint)globalX / 256) * 256;
|
||||
uint y = ((uint)globalY / 256) * 256;
|
||||
uint x = ((uint)globalX / Simulator.DefaultRegionSizeX) * Simulator.DefaultRegionSizeX;
|
||||
uint y = ((uint)globalY / Simulator.DefaultRegionSizeY) * Simulator.DefaultRegionSizeY;
|
||||
localX = globalX - (float)x;
|
||||
localY = globalY - (float)y;
|
||||
return Utils.UIntsToLong(x, y);
|
||||
|
||||
@@ -546,8 +546,8 @@ namespace OpenMetaverse
|
||||
|
||||
if (client.Settings.STORE_LAND_PATCHES)
|
||||
{
|
||||
Terrain = new TerrainPatch[16 * 16];
|
||||
WindSpeeds = new Vector2[16 * 16];
|
||||
Terrain = new TerrainPatch[sizeX/16 * sizeY/16];
|
||||
WindSpeeds = new Vector2[sizeX/16 * sizeY/16];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,18 +59,19 @@ namespace OpenMetaverse
|
||||
public int Range;
|
||||
public int QuantWBits;
|
||||
public int PatchIDs;
|
||||
public bool LargeRegion; // true if PatchIDs are 32 bits and not 10
|
||||
public uint WordBits;
|
||||
|
||||
public int X
|
||||
{
|
||||
get { return PatchIDs >> 5; }
|
||||
set { PatchIDs += (value << 5); }
|
||||
get { return PatchIDs >> (LargeRegion ? 16 : 5); }
|
||||
set { PatchIDs += (value << (LargeRegion ? 16 : 5)); }
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get { return PatchIDs & 0x1F; }
|
||||
set { PatchIDs |= value & 0x1F; }
|
||||
get { return PatchIDs & (LargeRegion ? 0xffff : 0x1F); }
|
||||
set { PatchIDs |= value & (LargeRegion ? 0xffff : 0x1F); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,14 +149,18 @@ namespace OpenMetaverse
|
||||
/// 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>
|
||||
/// specifying the height at each meter in the simulator.
|
||||
/// This can be larger if it is a varregion.</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}};
|
||||
var layerType = TerrainPatch.LayerType.Land;
|
||||
if (heightmap.Length > Simulator.DefaultRegionSizeY * Simulator.DefaultRegionSizeY)
|
||||
layerType = TerrainPatch.LayerType.LandExtended;
|
||||
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = (byte) layerType}};
|
||||
|
||||
TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
|
||||
{
|
||||
@@ -235,15 +240,18 @@ namespace OpenMetaverse
|
||||
return layer;
|
||||
}
|
||||
|
||||
public static void CreatePatch(BitPack output, float[] patchData, int x, int y)
|
||||
public static void CreatePatch(BitPack output, float[] patchData, int x, int y, bool largeRegion = false)
|
||||
{
|
||||
if (patchData.Length != 16 * 16)
|
||||
throw new ArgumentException("Patch data must be a 16x16 array");
|
||||
|
||||
TerrainPatch.Header header = PrescanPatch(patchData);
|
||||
header.LargeRegion = largeRegion;
|
||||
header.QuantWBits = 136;
|
||||
header.PatchIDs = (y & 0x1F);
|
||||
header.PatchIDs += (x << 5);
|
||||
if (largeRegion)
|
||||
header.PatchIDs = (x << 16) | (y & 0xffff);
|
||||
else
|
||||
header.PatchIDs = (x << 5) | (y & 0x1f);
|
||||
|
||||
// NOTE: No idea what prequant and postquant should be or what they do
|
||||
int[] patch = CompressPatch(patchData, header, 10);
|
||||
@@ -251,15 +259,18 @@ namespace OpenMetaverse
|
||||
EncodePatch(output, patch, 0, wbits);
|
||||
}
|
||||
|
||||
public static void CreatePatch(BitPack output, float[,] patchData, int x, int y)
|
||||
public static void CreatePatch(BitPack output, float[,] patchData, int x, int y, bool largeRegion = false)
|
||||
{
|
||||
if (patchData.Length != 16 * 16)
|
||||
throw new ArgumentException("Patch data must be a 16x16 array");
|
||||
|
||||
var header = PrescanPatch(patchData);
|
||||
header.LargeRegion = largeRegion;
|
||||
header.QuantWBits = 136;
|
||||
header.PatchIDs = (y & 0x1F);
|
||||
header.PatchIDs += (x << 5);
|
||||
if (largeRegion)
|
||||
header.PatchIDs = (x << 16) | (y & 0xffff);
|
||||
else
|
||||
header.PatchIDs = (x << 5) | (y & 0x1f);
|
||||
|
||||
// NOTE: No idea what prequant and postquant should be or what they do
|
||||
int[] patch = CompressPatch(patchData, header, 10);
|
||||
@@ -277,7 +288,7 @@ namespace OpenMetaverse
|
||||
/// 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)
|
||||
public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y, bool largeRegion = false)
|
||||
{
|
||||
if (heightmap.Length != 256 * 256)
|
||||
throw new ArgumentException("Heightmap data must be 256x256");
|
||||
@@ -286,9 +297,12 @@ namespace OpenMetaverse
|
||||
throw new ArgumentException("X and Y patch offsets must be from 0 to 15");
|
||||
|
||||
var header = PrescanPatch(heightmap, x, y);
|
||||
header.LargeRegion = largeRegion;
|
||||
header.QuantWBits = 136;
|
||||
header.PatchIDs = (y & 0x1F);
|
||||
header.PatchIDs += (x << 5);
|
||||
if (largeRegion)
|
||||
header.PatchIDs = (x << 16) | (y & 0xffff);
|
||||
else
|
||||
header.PatchIDs = (x << 5) | (y & 0x1f);
|
||||
|
||||
// NOTE: No idea what prequant and postquant should be or what they do
|
||||
int[] patch = CompressPatch(heightmap, x, y, header, 10);
|
||||
@@ -296,6 +310,8 @@ namespace OpenMetaverse
|
||||
EncodePatch(output, patch, 0, wbits);
|
||||
}
|
||||
|
||||
// Scan the height map to get the range of values so the values can be compressed.
|
||||
// Returns a TerrainPatch.Header with the range information filled in.
|
||||
private static TerrainPatch.Header PrescanPatch(float[] patch)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header();
|
||||
@@ -318,6 +334,8 @@ namespace OpenMetaverse
|
||||
return header;
|
||||
}
|
||||
|
||||
// Scan the height map to get the range of values so the values can be compressed.
|
||||
// Returns a TerrainPatch.Header with the range information filled in.
|
||||
private static TerrainPatch.Header PrescanPatch(float[,] patch)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header();
|
||||
@@ -340,6 +358,8 @@ namespace OpenMetaverse
|
||||
return header;
|
||||
}
|
||||
|
||||
// Scan the height map to get the range of values so the values can be compressed.
|
||||
// Returns a TerrainPatch.Header with the range information filled in.
|
||||
private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header();
|
||||
@@ -362,7 +382,7 @@ namespace OpenMetaverse
|
||||
return header;
|
||||
}
|
||||
|
||||
public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
|
||||
public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack, bool largeRegion = false)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
|
||||
|
||||
@@ -377,7 +397,9 @@ namespace OpenMetaverse
|
||||
header.Range = bitpack.UnpackBits(16);
|
||||
|
||||
// Patch IDs (10 bits)
|
||||
header.PatchIDs = bitpack.UnpackBits(10);
|
||||
|
||||
header.LargeRegion = largeRegion;
|
||||
header.PatchIDs = bitpack.UnpackBits(largeRegion ? 32 : 10);
|
||||
|
||||
// Word bits
|
||||
header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2);
|
||||
@@ -428,7 +450,7 @@ namespace OpenMetaverse
|
||||
output.PackBits(header.QuantWBits, 8);
|
||||
output.PackFloat(header.DCOffset);
|
||||
output.PackBits(header.Range, 16);
|
||||
output.PackBits(header.PatchIDs, 10);
|
||||
output.PackBits(header.PatchIDs, header.LargeRegion ? 32 : 10); // the IDs are larger for large regions
|
||||
|
||||
return wbits;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace OpenMetaverse
|
||||
Client.Network.RegisterCallback(PacketType.LayerData, LayerDataHandler);
|
||||
}
|
||||
|
||||
private void DecompressLand(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group)
|
||||
private void DecompressLand(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group, bool largeRegion = false)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
@@ -76,7 +76,7 @@ namespace OpenMetaverse
|
||||
|
||||
while (true)
|
||||
{
|
||||
TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack);
|
||||
TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion);
|
||||
|
||||
if (header.QuantWBits == TerrainCompressor.END_OF_PATCHES)
|
||||
break;
|
||||
@@ -84,7 +84,7 @@ namespace OpenMetaverse
|
||||
x = header.X;
|
||||
y = header.Y;
|
||||
|
||||
if (x >= TerrainCompressor.PATCHES_PER_EDGE || y >= TerrainCompressor.PATCHES_PER_EDGE)
|
||||
if (!largeRegion && (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}",
|
||||
@@ -117,7 +117,7 @@ namespace OpenMetaverse
|
||||
}
|
||||
}
|
||||
|
||||
private void DecompressWind(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group)
|
||||
private void DecompressWind(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group, bool largeRegion = false)
|
||||
{
|
||||
int[] patches = new int[32 * 32];
|
||||
|
||||
@@ -131,12 +131,12 @@ namespace OpenMetaverse
|
||||
// wind_direction = vec2(x,y)
|
||||
|
||||
// X values
|
||||
TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack);
|
||||
TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion);
|
||||
TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize);
|
||||
float[] xvalues = TerrainCompressor.DecompressPatch(patches, header, group);
|
||||
|
||||
// Y values
|
||||
header = TerrainCompressor.DecodePatchHeader(bitpack);
|
||||
header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion);
|
||||
TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize);
|
||||
float[] yvalues = TerrainCompressor.DecompressPatch(patches, header, group);
|
||||
|
||||
@@ -172,6 +172,10 @@ namespace OpenMetaverse
|
||||
if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES)
|
||||
DecompressLand(e.Simulator, bitpack, header);
|
||||
break;
|
||||
case TerrainPatch.LayerType.LandExtended:
|
||||
if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES)
|
||||
DecompressLand(e.Simulator, bitpack, header, true);
|
||||
break;
|
||||
case TerrainPatch.LayerType.Water:
|
||||
Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user