diff --git a/LibreMetaverse/Assets/Archiving/OarFile.cs b/LibreMetaverse/Assets/Archiving/OarFile.cs
index 99eb2a55..fc8d57fc 100644
--- a/LibreMetaverse/Assets/Archiving/OarFile.cs
+++ b/LibreMetaverse/Assets/Archiving/OarFile.cs
@@ -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);
diff --git a/LibreMetaverse/GridManager.cs b/LibreMetaverse/GridManager.cs
index e273a077..03f75a48 100644
--- a/LibreMetaverse/GridManager.cs
+++ b/LibreMetaverse/GridManager.cs
@@ -158,14 +158,15 @@ namespace OpenMetaverse
public uint GlobalY;
/// Get the Local X position of the item
- public uint LocalX { get { return GlobalX % 256; } }
+ public uint LocalX { get { return GlobalX % Simulator.DefaultRegionSizeX; } }
/// Get the Local Y position of the item
- public uint LocalY { get { return GlobalY % 256; } }
+ public uint LocalY { get { return GlobalY % Simulator.DefaultRegionSizeY; } }
/// Get the Handle of the region
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))); }
}
}
diff --git a/LibreMetaverse/Helpers.cs b/LibreMetaverse/Helpers.cs
index 9f3b09b2..45c6076f 100644
--- a/LibreMetaverse/Helpers.cs
+++ b/LibreMetaverse/Helpers.cs
@@ -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
///
+ ///
+ /// 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.
+ ///
/// The absolute X location, a number such as
/// 255360.35
/// The absolute Y location, a number such as
@@ -160,8 +165,8 @@ namespace OpenMetaverse
/// A 64-bit region handle that can be used to teleport to
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);
diff --git a/LibreMetaverse/Simulator.cs b/LibreMetaverse/Simulator.cs
index 79438ca0..2f82738c 100644
--- a/LibreMetaverse/Simulator.cs
+++ b/LibreMetaverse/Simulator.cs
@@ -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];
}
}
diff --git a/LibreMetaverse/TerrainCompressor.cs b/LibreMetaverse/TerrainCompressor.cs
index 43ffd4ae..d0d03504 100644
--- a/LibreMetaverse/TerrainCompressor.cs
+++ b/LibreMetaverse/TerrainCompressor.cs
@@ -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
///
/// A 256 * 256 array of floating point values
- /// specifying the height at each meter in the simulator
+ /// specifying the height at each meter in the simulator.
+ /// This can be larger if it is a varregion.
/// 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
///
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
/// Y offset of the patch to create, valid values are
/// from 0 to 15
- 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;
}
diff --git a/LibreMetaverse/TerrainManager.cs b/LibreMetaverse/TerrainManager.cs
index 8a112e94..71183ea8 100644
--- a/LibreMetaverse/TerrainManager.cs
+++ b/LibreMetaverse/TerrainManager.cs
@@ -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;