aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs362
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs12
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs5
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs79
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs352
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainCompressor.cs948
8 files changed, 1292 insertions, 486 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index b45cc4d..4ab5a4a 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -2221,14 +2221,9 @@ namespace OpenSim.Region.Framework.Scenes
2221 itemID = UUID.Zero; 2221 itemID = UUID.Zero;
2222 if (grp != null) 2222 if (grp != null)
2223 { 2223 {
2224 Vector3 inventoryStoredPosition = new Vector3 2224 Vector3 inventoryStoredPosition = new Vector3(
2225 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) 2225 Math.Min(grp.AbsolutePosition.X, RegionInfo.RegionSizeX - 6),
2226 ? 250 2226 Math.Min(grp.AbsolutePosition.Y, RegionInfo.RegionSizeY - 6),
2227 : grp.AbsolutePosition.X)
2228 ,
2229 (grp.AbsolutePosition.X > (int)Constants.RegionSize)
2230 ? 250
2231 : grp.AbsolutePosition.X,
2232 grp.AbsolutePosition.Z); 2227 grp.AbsolutePosition.Z);
2233 2228
2234 Vector3 originalPosition = grp.AbsolutePosition; 2229 Vector3 originalPosition = grp.AbsolutePosition;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index eb34f55..46c9048 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -6,7 +6,7 @@
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
@@ -103,7 +103,29 @@ namespace OpenSim.Region.Framework.Scenes
103 /// <summary> 103 /// <summary>
104 /// If false then physical objects are disabled, though collisions will continue as normal. 104 /// If false then physical objects are disabled, though collisions will continue as normal.
105 /// </summary> 105 /// </summary>
106 public bool PhysicsEnabled { get; set; } 106 public bool PhysicsEnabled
107 {
108 get
109 {
110 return m_physicsEnabled;
111 }
112
113 set
114 {
115 m_physicsEnabled = value;
116
117 if (PhysicsScene != null)
118 {
119 IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
120
121 if (physScene != null)
122 physScene.SetPhysicsParameter(
123 "Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
124 }
125 }
126 }
127
128 private bool m_physicsEnabled;
107 129
108 /// <summary> 130 /// <summary>
109 /// If false then scripts are not enabled on the smiulator 131 /// If false then scripts are not enabled on the smiulator
@@ -160,11 +182,6 @@ namespace OpenSim.Region.Framework.Scenes
160 /// </summary> 182 /// </summary>
161 public SimStatsReporter StatsReporter { get; private set; } 183 public SimStatsReporter StatsReporter { get; private set; }
162 184
163 public List<Border> NorthBorders = new List<Border>();
164 public List<Border> EastBorders = new List<Border>();
165 public List<Border> SouthBorders = new List<Border>();
166 public List<Border> WestBorders = new List<Border>();
167
168 /// <summary> 185 /// <summary>
169 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a 186 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
170 /// PhysicsScene in order to perform collision detection 187 /// PhysicsScene in order to perform collision detection
@@ -204,15 +221,16 @@ namespace OpenSim.Region.Framework.Scenes
204 /// </summary> 221 /// </summary>
205 public int m_linksetCapacity = 0; 222 public int m_linksetCapacity = 0;
206 223
224 public bool m_clampPrimSize;
225 public bool m_trustBinaries;
226 public bool m_allowScriptCrossings = true;
227
207 /// <summary> 228 /// <summary>
208 /// Max prims an Physical object will hold 229 /// Max prims an Physical object will hold
209 /// </summary> 230 /// </summary>
210 /// 231 ///
211 public int m_linksetPhysCapacity = 0; 232 public int m_linksetPhysCapacity = 0;
212 233
213 public bool m_clampPrimSize;
214 public bool m_trustBinaries;
215 public bool m_allowScriptCrossings;
216 public bool m_useFlySlow; 234 public bool m_useFlySlow;
217 public bool m_useTrashOnDelete = true; 235 public bool m_useTrashOnDelete = true;
218 236
@@ -364,7 +382,6 @@ namespace OpenSim.Region.Framework.Scenes
364 382
365 // TODO: Possibly stop other classes being able to manipulate this directly. 383 // TODO: Possibly stop other classes being able to manipulate this directly.
366 private SceneGraph m_sceneGraph; 384 private SceneGraph m_sceneGraph;
367 private volatile int m_bordersLocked;
368 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing 385 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
369 private volatile bool m_backingup; 386 private volatile bool m_backingup;
370 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 387 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
@@ -446,18 +463,6 @@ namespace OpenSim.Region.Framework.Scenes
446 set { m_splitRegionID = value; } 463 set { m_splitRegionID = value; }
447 } 464 }
448 465
449 public bool BordersLocked
450 {
451 get { return m_bordersLocked == 1; }
452 set
453 {
454 if (value == true)
455 m_bordersLocked = 1;
456 else
457 m_bordersLocked = 0;
458 }
459 }
460
461 public new float TimeDilation 466 public new float TimeDilation
462 { 467 {
463 get { return m_sceneGraph.PhysicsScene.TimeDilation; } 468 get { return m_sceneGraph.PhysicsScene.TimeDilation; }
@@ -1075,28 +1080,6 @@ namespace OpenSim.Region.Framework.Scenes
1075 PeriodicBackup = true; 1080 PeriodicBackup = true;
1076 UseBackup = true; 1081 UseBackup = true;
1077 1082
1078 BordersLocked = true;
1079 Border northBorder = new Border();
1080 northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeY); //<---
1081 northBorder.CrossDirection = Cardinals.N;
1082 NorthBorders.Add(northBorder);
1083
1084 Border southBorder = new Border();
1085 southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
1086 southBorder.CrossDirection = Cardinals.S;
1087 SouthBorders.Add(southBorder);
1088
1089 Border eastBorder = new Border();
1090 eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeX); //<---
1091 eastBorder.CrossDirection = Cardinals.E;
1092 EastBorders.Add(eastBorder);
1093
1094 Border westBorder = new Border();
1095 westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
1096 westBorder.CrossDirection = Cardinals.W;
1097 WestBorders.Add(westBorder);
1098 BordersLocked = false;
1099
1100 m_eventManager = new EventManager(); 1083 m_eventManager = new EventManager();
1101 1084
1102 m_permissions = new ScenePermissions(this); 1085 m_permissions = new ScenePermissions(this);
@@ -1975,7 +1958,7 @@ namespace OpenSim.Region.Framework.Scenes
1975 { 1958 {
1976 try 1959 try
1977 { 1960 {
1978 double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); 1961 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1979 if (map == null) 1962 if (map == null)
1980 { 1963 {
1981 // This should be in the Terrain module, but it isn't because 1964 // This should be in the Terrain module, but it isn't because
@@ -1986,7 +1969,7 @@ namespace OpenSim.Region.Framework.Scenes
1986 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 1969 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
1987 1970
1988 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 1971 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
1989 Heightmap = new TerrainChannel(m_InitialTerrain); 1972 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1990 1973
1991 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1974 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1992 } 1975 }
@@ -2611,185 +2594,35 @@ namespace OpenSim.Region.Framework.Scenes
2611 EntityTransferModule.Cross(grp, attemptedPosition, silent); 2594 EntityTransferModule.Cross(grp, attemptedPosition, silent);
2612 } 2595 }
2613 2596
2614 public Border GetCrossedBorder(Vector3 position, Cardinals gridline) 2597 // Simple test to see if a position is in the current region.
2598 // This test is mostly used to see if a region crossing is necessary.
2599 // Assuming the position is relative to the region so anything outside its bounds.
2600 // Return 'true' if position inside region.
2601 public bool PositionIsInCurrentRegion(Vector3 pos)
2615 { 2602 {
2616 if (BordersLocked) 2603 bool ret = false;
2617 { 2604 int xx = (int)Math.Floor(pos.X);
2618 switch (gridline) 2605 int yy = (int)Math.Floor(pos.Y);
2619 { 2606 if (xx < 0 || yy < 0)
2620 case Cardinals.N: 2607 return false;
2621 lock (NorthBorders)
2622 {
2623 foreach (Border b in NorthBorders)
2624 {
2625 if (b.TestCross(position))
2626 return b;
2627 }
2628 }
2629 break;
2630 case Cardinals.S:
2631 lock (SouthBorders)
2632 {
2633 foreach (Border b in SouthBorders)
2634 {
2635 if (b.TestCross(position))
2636 return b;
2637 }
2638 }
2639
2640 break;
2641 case Cardinals.E:
2642 lock (EastBorders)
2643 {
2644 foreach (Border b in EastBorders)
2645 {
2646 if (b.TestCross(position))
2647 return b;
2648 }
2649 }
2650
2651 break;
2652 case Cardinals.W:
2653
2654 lock (WestBorders)
2655 {
2656 foreach (Border b in WestBorders)
2657 {
2658 if (b.TestCross(position))
2659 return b;
2660 }
2661 }
2662 break;
2663 2608
2664 } 2609 IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>();
2610 if (regionCombinerModule == null)
2611 {
2612 // Regular region. Just check for region size
2613 if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY )
2614 ret = true;
2665 } 2615 }
2666 else 2616 else
2667 { 2617 {
2668 switch (gridline) 2618 // We're in a mega-region so see if we are still in that larger region
2669 { 2619 ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
2670 case Cardinals.N:
2671 foreach (Border b in NorthBorders)
2672 {
2673 if (b.TestCross(position))
2674 return b;
2675 }
2676
2677 break;
2678 case Cardinals.S:
2679 foreach (Border b in SouthBorders)
2680 {
2681 if (b.TestCross(position))
2682 return b;
2683 }
2684 break;
2685 case Cardinals.E:
2686 foreach (Border b in EastBorders)
2687 {
2688 if (b.TestCross(position))
2689 return b;
2690 }
2691
2692 break;
2693 case Cardinals.W:
2694 foreach (Border b in WestBorders)
2695 {
2696 if (b.TestCross(position))
2697 return b;
2698 }
2699 break;
2700
2701 }
2702 } 2620 }
2703 2621
2704 return null; 2622 return ret;
2705 }
2706 2623
2707 public bool TestBorderCross(Vector3 position, Cardinals border)
2708 {
2709 if (BordersLocked)
2710 {
2711 switch (border)
2712 {
2713 case Cardinals.N:
2714 lock (NorthBorders)
2715 {
2716 foreach (Border b in NorthBorders)
2717 {
2718 if (b.TestCross(position))
2719 return true;
2720 }
2721 }
2722 break;
2723 case Cardinals.E:
2724 lock (EastBorders)
2725 {
2726 foreach (Border b in EastBorders)
2727 {
2728 if (b.TestCross(position))
2729 return true;
2730 }
2731 }
2732 break;
2733 case Cardinals.S:
2734 lock (SouthBorders)
2735 {
2736 foreach (Border b in SouthBorders)
2737 {
2738 if (b.TestCross(position))
2739 return true;
2740 }
2741 }
2742 break;
2743 case Cardinals.W:
2744 lock (WestBorders)
2745 {
2746 foreach (Border b in WestBorders)
2747 {
2748 if (b.TestCross(position))
2749 return true;
2750 }
2751 }
2752 break;
2753 }
2754 }
2755 else
2756 {
2757 switch (border)
2758 {
2759 case Cardinals.N:
2760 foreach (Border b in NorthBorders)
2761 {
2762 if (b.TestCross(position))
2763 return true;
2764 }
2765 break;
2766 case Cardinals.E:
2767 foreach (Border b in EastBorders)
2768 {
2769 if (b.TestCross(position))
2770 return true;
2771 }
2772 break;
2773 case Cardinals.S:
2774 foreach (Border b in SouthBorders)
2775 {
2776 if (b.TestCross(position))
2777 return true;
2778 }
2779 break;
2780 case Cardinals.W:
2781 foreach (Border b in WestBorders)
2782 {
2783 if (b.TestCross(position))
2784 return true;
2785 }
2786 break;
2787 }
2788 }
2789 return false;
2790 } 2624 }
2791 2625
2792
2793 /// <summary> 2626 /// <summary>
2794 /// Called when objects or attachments cross the border, or teleport, between regions. 2627 /// Called when objects or attachments cross the border, or teleport, between regions.
2795 /// </summary> 2628 /// </summary>
@@ -4116,60 +3949,11 @@ namespace OpenSim.Region.Framework.Scenes
4116 { 3949 {
4117// CleanDroppedAttachments(); 3950// CleanDroppedAttachments();
4118 3951
4119 if (TestBorderCross(acd.startpos, Cardinals.E)) 3952 // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
4120 { 3953 if (acd.startpos.X < 0) acd.startpos.X = 1f;
4121 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E); 3954 if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
4122 acd.startpos.X = crossedBorder.BorderLine.Z - 1; 3955 if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
4123 } 3956 if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
4124
4125 if (TestBorderCross(acd.startpos, Cardinals.N))
4126 {
4127 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
4128 acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
4129 }
4130
4131 //Mitigate http://opensimulator.org/mantis/view.php?id=3522
4132 // Check if start position is outside of region
4133 // If it is, check the Z start position also.. if not, leave it alone.
4134 if (BordersLocked)
4135 {
4136 lock (EastBorders)
4137 {
4138 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
4139 {
4140 m_log.Warn("FIX AGENT POSITION");
4141 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
4142 if (acd.startpos.Z > 720)
4143 acd.startpos.Z = 720;
4144 }
4145 }
4146 lock (NorthBorders)
4147 {
4148 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
4149 {
4150 m_log.Warn("FIX Agent POSITION");
4151 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
4152 if (acd.startpos.Z > 720)
4153 acd.startpos.Z = 720;
4154 }
4155 }
4156 } else
4157 {
4158 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
4159 {
4160 m_log.Warn("FIX AGENT POSITION");
4161 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
4162 if (acd.startpos.Z > 720)
4163 acd.startpos.Z = 720;
4164 }
4165 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
4166 {
4167 m_log.Warn("FIX Agent POSITION");
4168 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
4169 if (acd.startpos.Z > 720)
4170 acd.startpos.Z = 720;
4171 }
4172 }
4173 3957
4174// m_log.DebugFormat( 3958// m_log.DebugFormat(
4175// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}", 3959// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
@@ -4883,44 +4667,6 @@ namespace OpenSim.Region.Framework.Scenes
4883 ScenePresence sp = GetScenePresence(remoteClient.AgentId); 4667 ScenePresence sp = GetScenePresence(remoteClient.AgentId);
4884 if (sp != null) 4668 if (sp != null)
4885 { 4669 {
4886 uint regionX = RegionInfo.RegionLocX;
4887 uint regionY = RegionInfo.RegionLocY;
4888
4889 Utils.LongToUInts(regionHandle, out regionX, out regionY);
4890
4891 int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize;
4892 int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize;
4893
4894 position.X += shiftx;
4895 position.Y += shifty;
4896
4897 bool result = false;
4898
4899 if (TestBorderCross(position,Cardinals.N))
4900 result = true;
4901
4902 if (TestBorderCross(position, Cardinals.S))
4903 result = true;
4904
4905 if (TestBorderCross(position, Cardinals.E))
4906 result = true;
4907
4908 if (TestBorderCross(position, Cardinals.W))
4909 result = true;
4910
4911 // bordercross if position is outside of region
4912
4913 if (!result)
4914 {
4915 regionHandle = RegionInfo.RegionHandle;
4916 }
4917 else
4918 {
4919 // not in this region, undo the shift!
4920 position.X -= shiftx;
4921 position.Y -= shifty;
4922 }
4923
4924 if (EntityTransferModule != null) 4670 if (EntityTransferModule != null)
4925 { 4671 {
4926 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); 4672 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 52f46f2..a2625c4 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -52,6 +52,7 @@ namespace OpenSim.Region.Framework.Scenes
52 public class SceneCommunicationService //one instance per region 52 public class SceneCommunicationService //one instance per region
53 { 53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private static string LogHeader = "[SCENE COMMUNICATION SERVICE]";
55 56
56 protected RegionInfo m_regionInfo; 57 protected RegionInfo m_regionInfo;
57 protected Scene m_scene; 58 protected Scene m_scene;
@@ -100,7 +101,7 @@ namespace OpenSim.Region.Framework.Scenes
100 { 101 {
101 m_log.WarnFormat( 102 m_log.WarnFormat(
102 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.", 103 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.",
103 m_scene.Name, x / Constants.RegionSize, y / Constants.RegionSize); 104 m_scene.Name, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
104 } 105 }
105 } 106 }
106 107
@@ -166,7 +167,7 @@ namespace OpenSim.Region.Framework.Scenes
166 // we only want to send one update to each simulator; the simulator will 167 // we only want to send one update to each simulator; the simulator will
167 // hand it off to the regions where a child agent exists, this does assume 168 // hand it off to the regions where a child agent exists, this does assume
168 // that the region position is cached or performance will degrade 169 // that the region position is cached or performance will degrade
169 Utils.LongToUInts(regionHandle, out x, out y); 170 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
170 GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); 171 GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
171 if (dest == null) 172 if (dest == null)
172 continue; 173 continue;
@@ -206,7 +207,7 @@ namespace OpenSim.Region.Framework.Scenes
206 207
207 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); 208 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
208 uint x = 0, y = 0; 209 uint x = 0, y = 0;
209 Utils.LongToUInts(regionHandle, out x, out y); 210 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
210 211
211 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 212 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
212 213
@@ -226,6 +227,8 @@ namespace OpenSim.Region.Framework.Scenes
226 { 227 {
227 foreach (ulong handle in regionslst) 228 foreach (ulong handle in regionslst)
228 { 229 {
230 // We must take a copy here since handle acts like a reference when used in an iterator.
231 // This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region.
229 ulong handleCopy = handle; 232 ulong handleCopy = handle;
230 Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); }); 233 Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); });
231 } 234 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 89c7a1a..cb2f377 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -412,7 +412,7 @@ namespace OpenSim.Region.Framework.Scenes
412 { 412 {
413 get 413 get
414 { 414 {
415 Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); 415 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
416 Vector3 maxScale = Vector3.Zero; 416 Vector3 maxScale = Vector3.Zero;
417 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 417 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
418 418
@@ -529,12 +529,10 @@ namespace OpenSim.Region.Framework.Scenes
529 set 529 set
530 { 530 {
531 Vector3 val = value; 531 Vector3 val = value;
532 if (Scene != null && !IsAttachmentCheckFull() 532 if (Scene != null
533 && !Scene.LoadingPrims && 533 && Scene.PositionIsInCurrentRegion(val)
534 (Scene.TestBorderCross(val, Cardinals.E) || 534 && !IsAttachmentCheckFull()
535 Scene.TestBorderCross(val, Cardinals.W) || 535 && !Scene.LoadingPrims
536 Scene.TestBorderCross(val, Cardinals.N) ||
537 Scene.TestBorderCross(val, Cardinals.S))
538 ) 536 )
539 { 537 {
540 if (!inTransit) 538 if (!inTransit)
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 91293c4..8979659 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -2979,10 +2979,7 @@ namespace OpenSim.Region.Framework.Scenes
2979 { 2979 {
2980 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0); 2980 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
2981 2981
2982 if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N) 2982 if (!ParentGroup.Scene.PositionIsInCurrentRegion(newpos))
2983 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
2984 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
2985 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
2986 { 2983 {
2987 ParentGroup.AbsolutePosition = newpos; 2984 ParentGroup.AbsolutePosition = newpos;
2988 return; 2985 return;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index dff582b..3e278a9 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -842,9 +842,8 @@ namespace OpenSim.Region.Framework.Scenes
842 foreach (ulong handle in seeds.Keys) 842 foreach (ulong handle in seeds.Keys)
843 { 843 {
844 uint x, y; 844 uint x, y;
845 Utils.LongToUInts(handle, out x, out y); 845 Util.RegionHandleToRegionLoc(handle, out x, out y);
846 x = x / Constants.RegionSize; 846
847 y = y / Constants.RegionSize;
848 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) 847 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
849 { 848 {
850 old.Add(handle); 849 old.Add(handle);
@@ -866,9 +865,7 @@ namespace OpenSim.Region.Framework.Scenes
866 foreach (KeyValuePair<ulong, string> kvp in KnownRegions) 865 foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
867 { 866 {
868 uint x, y; 867 uint x, y;
869 Utils.LongToUInts(kvp.Key, out x, out y); 868 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
870 x = x / Constants.RegionSize;
871 y = y / Constants.RegionSize;
872 m_log.Info(" >> "+x+", "+y+": "+kvp.Value); 869 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
873 } 870 }
874 } 871 }
@@ -1170,18 +1167,6 @@ namespace OpenSim.Region.Framework.Scenes
1170 1167
1171 if (ParentID == 0) 1168 if (ParentID == 0)
1172 { 1169 {
1173 if (m_scene.TestBorderCross(pos, Cardinals.E))
1174 {
1175 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
1176 pos.X = crossedBorder.BorderLine.Z - 1;
1177 }
1178
1179 if (m_scene.TestBorderCross(pos, Cardinals.N))
1180 {
1181 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
1182 pos.Y = crossedBorder.BorderLine.Z - 1;
1183 }
1184
1185 CheckAndAdjustLandingPoint(ref pos); 1170 CheckAndAdjustLandingPoint(ref pos);
1186 1171
1187 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) 1172 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
@@ -1201,7 +1186,7 @@ namespace OpenSim.Region.Framework.Scenes
1201 1186
1202 float posZLimit = 0; 1187 float posZLimit = 0;
1203 1188
1204 if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize) 1189 if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
1205 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; 1190 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
1206 1191
1207 float newPosZ = posZLimit + localAVHeight / 2; 1192 float newPosZ = posZLimit + localAVHeight / 2;
@@ -2612,7 +2597,7 @@ namespace OpenSim.Region.Framework.Scenes
2612 if (regionCombinerModule != null) 2597 if (regionCombinerModule != null)
2613 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); 2598 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
2614 else 2599 else
2615 regionSize = new Vector2(Constants.RegionSize); 2600 regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
2616 2601
2617 if (pos.X < 0 || pos.X >= regionSize.X 2602 if (pos.X < 0 || pos.X >= regionSize.X
2618 || pos.Y < 0 || pos.Y >= regionSize.Y 2603 || pos.Y < 0 || pos.Y >= regionSize.Y
@@ -2630,8 +2615,8 @@ namespace OpenSim.Region.Framework.Scenes
2630// } 2615// }
2631 2616
2632 // Get terrain height for sub-region in a megaregion if necessary 2617 // Get terrain height for sub-region in a megaregion if necessary
2633 int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); 2618 int X = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
2634 int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); 2619 int Y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
2635 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y); 2620 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
2636 // If X and Y is NaN, target_region will be null 2621 // If X and Y is NaN, target_region will be null
2637 if (target_region == null) 2622 if (target_region == null)
@@ -2642,7 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes
2642 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) 2627 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
2643 targetScene = m_scene; 2628 targetScene = m_scene;
2644 2629
2645 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)]; 2630 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
2646 // dont try to land underground 2631 // dont try to land underground
2647 terrainHeight += Appearance.AvatarHeight / 2; 2632 terrainHeight += Appearance.AvatarHeight / 2;
2648 pos.Z = Math.Max(terrainHeight, pos.Z); 2633 pos.Z = Math.Max(terrainHeight, pos.Z);
@@ -3872,32 +3857,28 @@ namespace OpenSim.Region.Framework.Scenes
3872// m_log.DebugFormat( 3857// m_log.DebugFormat(
3873// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}", 3858// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
3874// pos2, Name, Scene.Name); 3859// pos2, Name, Scene.Name);
3875 3860
3876 if( Scene.TestBorderCross(pos2, Cardinals.E) || 3861 if (Scene.PositionIsInCurrentRegion(pos2))
3877 Scene.TestBorderCross(pos2, Cardinals.W) || 3862 return;
3878 Scene.TestBorderCross(pos2, Cardinals.N) || 3863
3879 Scene.TestBorderCross(pos2, Cardinals.S) 3864 if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero)
3880 )
3881 { 3865 {
3882 if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero) 3866 // we don't have entity transfer module
3883 { 3867 Vector3 pos = AbsolutePosition;
3884 // we don't have entity transfer module 3868 float px = pos.X;
3885 Vector3 pos = AbsolutePosition; 3869 if (px < 0)
3886 float px = pos.X; 3870 pos.X += Velocity.X * 2;
3887 if (px < 0) 3871 else if (px > m_scene.RegionInfo.RegionSizeX)
3888 pos.X += Velocity.X * 2; 3872 pos.X -= Velocity.X * 2;
3889 else if (px > m_scene.RegionInfo.RegionSizeX)
3890 pos.X -= Velocity.X * 2;
3891 3873
3892 float py = pos.Y; 3874 float py = pos.Y;
3893 if (py < 0) 3875 if (py < 0)
3894 pos.Y += Velocity.Y * 2; 3876 pos.Y += Velocity.Y * 2;
3895 else if (py > m_scene.RegionInfo.RegionSizeY) 3877 else if (py > m_scene.RegionInfo.RegionSizeY)
3896 pos.Y -= Velocity.Y * 2; 3878 pos.Y -= Velocity.Y * 2;
3897 3879
3898 Velocity = Vector3.Zero; 3880 Velocity = Vector3.Zero;
3899 AbsolutePosition = pos; 3881 AbsolutePosition = pos;
3900 }
3901 } 3882 }
3902 } 3883 }
3903 3884
@@ -3962,7 +3943,7 @@ namespace OpenSim.Region.Framework.Scenes
3962 3943
3963 // Put the child agent back at the center 3944 // Put the child agent back at the center
3964 AbsolutePosition 3945 AbsolutePosition
3965 = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70); 3946 = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
3966 3947
3967 Animator.ResetAnimations(); 3948 Animator.ResetAnimations();
3968 } 3949 }
@@ -3989,9 +3970,7 @@ namespace OpenSim.Region.Framework.Scenes
3989 if (handle != Scene.RegionInfo.RegionHandle) 3970 if (handle != Scene.RegionInfo.RegionHandle)
3990 { 3971 {
3991 uint x, y; 3972 uint x, y;
3992 Utils.LongToUInts(handle, out x, out y); 3973 Util.RegionHandleToRegionLoc(handle, out x, out y);
3993 x = x / Constants.RegionSize;
3994 y = y / Constants.RegionSize;
3995 3974
3996// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); 3975// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
3997// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); 3976// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index b6e0a97..3d563a6 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,21 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces;
30using System; 28using System;
29using System.IO;
31using System.Text; 30using System.Text;
31using System.Reflection;
32using System.Xml; 32using System.Xml;
33using System.IO;
34using System.Xml.Serialization; 33using System.Xml.Serialization;
35 34
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38
39using OpenMetaverse;
40
41using log4net;
42
36namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
37{ 44{
38 /// <summary> 45 /// <summary>
@@ -40,140 +47,136 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 47 /// </summary>
41 public class TerrainChannel : ITerrainChannel 48 public class TerrainChannel : ITerrainChannel
42 { 49 {
43 private readonly bool[,] taint; 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 private double[,] map; 51 private static string LogHeader = "[TERRAIN CHANNEL]";
45 52
53 protected TerrainData m_terrainData;
54
55 public int Width { get { return m_terrainData.SizeX; } } // X dimension
56 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
57 public int Height { get { return m_terrainData.SizeY; } } // Y dimension
58 public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
59
60 // Default, not-often-used builder
46 public TerrainChannel() 61 public TerrainChannel()
47 { 62 {
48 map = new double[Constants.RegionSize, Constants.RegionSize]; 63 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
49 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 64 FlatLand();
50 65 // PinHeadIsland();
51 PinHeadIsland();
52 } 66 }
53 67
54 public TerrainChannel(String type) 68 // Create terrain of given size
69 public TerrainChannel(int pX, int pY)
55 { 70 {
56 map = new double[Constants.RegionSize, Constants.RegionSize]; 71 m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
57 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 72 }
58 73
74 // Create terrain of specified size and initialize with specified terrain.
75 // TODO: join this with the terrain initializers.
76 public TerrainChannel(String type, int pX, int pY, int pZ)
77 {
78 m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
59 if (type.Equals("flat")) 79 if (type.Equals("flat"))
60 FlatLand(); 80 FlatLand();
61 else 81 else
62 PinHeadIsland(); 82 PinHeadIsland();
63 } 83 }
64 84
65 public TerrainChannel(double[,] import) 85 // Create channel passed a heightmap and expected dimensions of the region.
86 // The heightmap might not fit the passed size so accomodations must be made.
87 public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
66 { 88 {
67 map = import; 89 int hmSizeX = pM.GetLength(0);
68 taint = new bool[import.GetLength(0),import.GetLength(1)]; 90 int hmSizeY = pM.GetLength(1);
69 }
70 91
71 public TerrainChannel(bool createMap) 92 m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
72 { 93
73 if (createMap) 94 for (int xx = 0; xx < pSizeX; xx++)
74 { 95 for (int yy = 0; yy < pSizeY; yy++)
75 map = new double[Constants.RegionSize,Constants.RegionSize]; 96 if (xx > hmSizeX || yy > hmSizeY)
76 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16]; 97 m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
77 } 98 else
99 m_terrainData[xx, yy] = (float)pM[xx, yy];
78 } 100 }
79 101
80 public TerrainChannel(int w, int h) 102 public TerrainChannel(TerrainData pTerrData)
81 { 103 {
82 map = new double[w,h]; 104 m_terrainData = pTerrData;
83 taint = new bool[w / 16,h / 16];
84 } 105 }
85 106
86 #region ITerrainChannel Members 107 #region ITerrainChannel Members
87 108
88 public int Width 109 // ITerrainChannel.MakeCopy()
110 public ITerrainChannel MakeCopy()
89 { 111 {
90 get { return map.GetLength(0); } 112 return this.Copy();
91 } 113 }
92 114
93 public int Height 115 // ITerrainChannel.GetTerrainData()
116 public TerrainData GetTerrainData()
94 { 117 {
95 get { return map.GetLength(1); } 118 return m_terrainData;
96 } 119 }
97 120
98 public ITerrainChannel MakeCopy() 121 // ITerrainChannel.GetFloatsSerialized()
122 // This one dimensional version is ordered so height = map[y*sizeX+x];
123 // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
124 // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
125 public float[] GetFloatsSerialised()
99 { 126 {
100 TerrainChannel copy = new TerrainChannel(false); 127 return m_terrainData.GetFloatsSerialized();
101 copy.map = (double[,]) map.Clone();
102
103 return copy;
104 } 128 }
105 129
106 public float[] GetFloatsSerialised() 130 // ITerrainChannel.GetDoubles()
131 public double[,] GetDoubles()
107 { 132 {
108 // Move the member variables into local variables, calling 133 double[,] heights = new double[Width, Height];
109 // member variables 256*256 times gets expensive
110 int w = Width;
111 int h = Height;
112 float[] heights = new float[w * h];
113 134
114 int i, j; // map coordinates
115 int idx = 0; // index into serialized array 135 int idx = 0; // index into serialized array
116 for (i = 0; i < h; i++) 136 for (int ii = 0; ii < Width; ii++)
117 { 137 {
118 for (j = 0; j < w; j++) 138 for (int jj = 0; jj < Height; jj++)
119 { 139 {
120 heights[idx++] = (float)map[j, i]; 140 heights[ii, jj] = (double)m_terrainData[ii, jj];
141 idx++;
121 } 142 }
122 } 143 }
123 144
124 return heights; 145 return heights;
125 } 146 }
126 147
127 public double[,] GetDoubles() 148 // ITerrainChannel.this[x,y]
128 {
129 return map;
130 }
131
132 public double this[int x, int y] 149 public double this[int x, int y]
133 { 150 {
134 get 151 get {
135 { 152 if (x < 0 || x >= Width || y < 0 || y >= Height)
136 if (x < 0) x = 0; 153 return 0;
137 if (y < 0) y = 0; 154 return (double)m_terrainData[x, y];
138 if (x >= (int)Constants.RegionSize) x = (int)Constants.RegionSize - 1;
139 if (y >= (int)Constants.RegionSize) y = (int)Constants.RegionSize - 1;
140
141 return map[x, y];
142 } 155 }
143 set 156 set
144 { 157 {
145 // Will "fix" terrain hole problems. Although not fantastically.
146 if (Double.IsNaN(value) || Double.IsInfinity(value)) 158 if (Double.IsNaN(value) || Double.IsInfinity(value))
147 return; 159 return;
148 160
149 if (map[x, y] != value) 161 m_terrainData[x, y] = (float)value;
150 {
151 taint[x / 16, y / 16] = true;
152 map[x, y] = value;
153 }
154 } 162 }
155 } 163 }
156 164
157 public bool Tainted(int x, int y) 165 // ITerrainChannel.GetHieghtAtXYZ(x, y, z)
166 public float GetHeightAtXYZ(float x, float y, float z)
158 { 167 {
159 if (taint[x / 16, y / 16]) 168 if (x < 0 || x >= Width || y < 0 || y >= Height)
160 { 169 return 0;
161 taint[x / 16, y / 16] = false; 170 return m_terrainData[(int)x, (int)y];
162 return true;
163 }
164 return false;
165 } 171 }
166 172
167 #endregion 173 // ITerrainChannel.Tainted()
168 174 public bool Tainted(int x, int y)
169 public TerrainChannel Copy()
170 { 175 {
171 TerrainChannel copy = new TerrainChannel(false); 176 return m_terrainData.IsTaintedAt(x, y);
172 copy.map = (double[,]) map.Clone();
173
174 return copy;
175 } 177 }
176 178
179 // ITerrainChannel.SaveToXmlString()
177 public string SaveToXmlString() 180 public string SaveToXmlString()
178 { 181 {
179 XmlWriterSettings settings = new XmlWriterSettings(); 182 XmlWriterSettings settings = new XmlWriterSettings();
@@ -189,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
189 } 192 }
190 } 193 }
191 194
192 private void WriteXml(XmlWriter writer) 195 // ITerrainChannel.LoadFromXmlString()
193 {
194 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
195 ToXml(writer);
196 writer.WriteEndElement();
197 }
198
199 public void LoadFromXmlString(string data) 196 public void LoadFromXmlString(string data)
200 { 197 {
201 StringReader sr = new StringReader(data); 198 StringReader sr = new StringReader(data);
@@ -207,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes
207 sr.Close(); 204 sr.Close();
208 } 205 }
209 206
207 // ITerrainChannel.Merge
208 public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
209 {
210 m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
211 newTerrain.Width, newTerrain.Height,
212 displacement, radianRotation, rotationDisplacement,
213 m_terrainData.SizeX, m_terrainData.SizeY);
214 for (int xx = 0; xx < newTerrain.Width; xx++)
215 {
216 for (int yy = 0; yy < newTerrain.Height; yy++)
217 {
218 int dispX = (int)displacement.X;
219 int dispY = (int)displacement.Y;
220 float newHeight = (float)newTerrain[xx, yy] + displacement.Z;
221 if (radianRotation == 0)
222 {
223 // If no rotation, place the new height in the specified location
224 dispX += xx;
225 dispY += yy;
226 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
227 {
228 m_terrainData[dispX, dispY] = newHeight;
229 }
230 }
231 else
232 {
233 // If rotating, we have to smooth the result because the conversion
234 // to ints will mean heightmap entries will not get changed
235 // First compute the rotation location for the new height.
236 dispX += (int)(rotationDisplacement.X
237 + ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation)
238 - ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) );
239
240 dispY += (int)(rotationDisplacement.Y
241 + ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation)
242 + ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) );
243
244 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
245 {
246 float oldHeight = m_terrainData[dispX, dispY];
247 // Smooth the heights around this location if the old height is far from this one
248 for (int sxx = dispX - 2; sxx < dispX + 2; sxx++)
249 {
250 for (int syy = dispY - 2; syy < dispY + 2; syy++)
251 {
252 if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY)
253 {
254 if (sxx == dispX && syy == dispY)
255 {
256 // Set height for the exact rotated point
257 m_terrainData[dispX, dispY] = newHeight;
258 }
259 else
260 {
261 if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f)
262 {
263 // If the adjacent height is far off, force it to this height
264 m_terrainData[sxx, syy] = newHeight;
265 }
266 }
267 }
268 }
269 }
270 }
271
272 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
273 {
274 m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy];
275 }
276 }
277 }
278 }
279 }
280
281 #endregion
282
283 public TerrainChannel Copy()
284 {
285 TerrainChannel copy = new TerrainChannel();
286 copy.m_terrainData = m_terrainData.Clone();
287 return copy;
288 }
289
290 private void WriteXml(XmlWriter writer)
291 {
292 if (Width == Constants.RegionSize && Height == Constants.RegionSize)
293 {
294 // Downward compatibility for legacy region terrain maps.
295 // If region is exactly legacy size, return the old format XML.
296 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
297 ToXml(writer);
298 writer.WriteEndElement();
299 }
300 else
301 {
302 // New format XML that includes width and length.
303 writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
304 ToXml2(writer);
305 writer.WriteEndElement();
306 }
307 }
308
210 private void ReadXml(XmlReader reader) 309 private void ReadXml(XmlReader reader)
211 { 310 {
212 reader.ReadStartElement("TerrainMap"); 311 // Check the first element. If legacy element, use the legacy reader.
213 FromXml(reader); 312 if (reader.IsStartElement("TerrainMap"))
313 {
314 reader.ReadStartElement("TerrainMap");
315 FromXml(reader);
316 }
317 else
318 {
319 reader.ReadStartElement("TerrainMap2");
320 FromXml2(reader);
321 }
214 } 322 }
215 323
324 // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
216 private void ToXml(XmlWriter xmlWriter) 325 private void ToXml(XmlWriter xmlWriter)
217 { 326 {
218 float[] mapData = GetFloatsSerialised(); 327 float[] mapData = GetFloatsSerialised();
@@ -226,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes
226 serializer.Serialize(xmlWriter, buffer); 335 serializer.Serialize(xmlWriter, buffer);
227 } 336 }
228 337
338 // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
229 private void FromXml(XmlReader xmlReader) 339 private void FromXml(XmlReader xmlReader)
230 { 340 {
231 XmlSerializer serializer = new XmlSerializer(typeof(byte[])); 341 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
232 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 342 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
233 int index = 0; 343 int index = 0;
234 344
345 m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
346
235 for (int y = 0; y < Height; y++) 347 for (int y = 0; y < Height; y++)
236 { 348 {
237 for (int x = 0; x < Width; x++) 349 for (int x = 0; x < Width; x++)
@@ -244,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes
244 } 356 }
245 } 357 }
246 358
359 private class TerrainChannelXMLPackage
360 {
361 public int Version;
362 public int SizeX;
363 public int SizeY;
364 public int SizeZ;
365 public float CompressionFactor;
366 public int[] Map;
367 public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap)
368 {
369 Version = 1;
370 SizeX = pX;
371 SizeY = pY;
372 SizeZ = pZ;
373 CompressionFactor = pCompressionFactor;
374 Map = pMap;
375 }
376 }
377
378 // New terrain serialization format that includes the width and length.
379 private void ToXml2(XmlWriter xmlWriter)
380 {
381 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor,
382 m_terrainData.GetCompressedMap());
383 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
384 serializer.Serialize(xmlWriter, package);
385 }
386
387 // New terrain serialization format that includes the width and length.
388 private void FromXml2(XmlReader xmlReader)
389 {
390 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
391 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
392 m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ);
393 }
394
395 // Fill the heightmap with the center bump terrain
247 private void PinHeadIsland() 396 private void PinHeadIsland()
248 { 397 {
249 int x; 398 for (int x = 0; x < Width; x++)
250 for (x = 0; x < Constants.RegionSize; x++)
251 { 399 {
252 int y; 400 for (int y = 0; y < Height; y++)
253 for (y = 0; y < Constants.RegionSize; y++)
254 { 401 {
255 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; 402 m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
256 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; 403 float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
257 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; 404 float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
258 if (map[x, y] < spherFacA) 405 if (m_terrainData[x, y]< spherFacA)
259 map[x, y] = spherFacA; 406 m_terrainData[x, y]= spherFacA;
260 if (map[x, y] < spherFacB) 407 if (m_terrainData[x, y]< spherFacB)
261 map[x, y] = spherFacB; 408 m_terrainData[x, y] = spherFacB;
262 } 409 }
263 } 410 }
264 } 411 }
265 412
266 private void FlatLand() 413 private void FlatLand()
267 { 414 {
268 int x; 415 m_terrainData.ClearLand();
269 for (x = 0; x < Constants.RegionSize; x++)
270 {
271 int y;
272 for (y = 0; y < Constants.RegionSize; y++)
273 map[x, y] = 21;
274 }
275 } 416 }
276
277 } 417 }
278} 418}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
new file mode 100644
index 0000000..fc8f8cd
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
@@ -0,0 +1,948 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Freely adapted from the Aurora version of the terrain compressor.
29 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
30 */
31
32using System;
33using System.Reflection;
34
35using log4net;
36
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Scenes;
40
41using OpenMetaverse;
42using OpenMetaverse.Packets;
43
44namespace OpenSim.Region.ClientStack.LindenUDP
45{
46 public static class OpenSimTerrainCompressor
47 {
48// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50#pragma warning disable 414
51 private static string LogHeader = "[TERRAIN COMPRESSOR]";
52#pragma warning restore 414
53
54 public const int END_OF_PATCHES = 97;
55
56 private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
57 private const int STRIDE = 264;
58
59 private const int ZERO_CODE = 0x0;
60 private const int ZERO_EOB = 0x2;
61 private const int POSITIVE_VALUE = 0x6;
62 private const int NEGATIVE_VALUE = 0x7;
63
64 private static readonly float[] DequantizeTable16 =
65 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
66
67 private static readonly float[] DequantizeTable32 =
68 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
69
70 private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
71 //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
72 private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
73 private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
74
75 private static readonly float[] QuantizeTable16 =
76 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
77
78 static OpenSimTerrainCompressor()
79 {
80 // Initialize the decompression tables
81 BuildDequantizeTable16();
82 SetupCosines16();
83 BuildCopyMatrix16();
84 BuildQuantizeTable16();
85 }
86
87 // Used to send cloud and wind patches
88 public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
89 int pRegionSizeY)
90 {
91 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
92
93 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
94 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
95
96 // Should be enough to fit even the most poorly packed data
97 byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
98 BitPack bitpack = new BitPack(data, 0);
99 bitpack.PackBits(header.Stride, 16);
100 bitpack.PackBits(header.PatchSize, 8);
101 bitpack.PackBits(type, 8);
102
103 foreach (TerrainPatch t in patches)
104 CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
105
106 bitpack.PackBits(END_OF_PATCHES, 8);
107
108 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
109 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
110
111 return layer;
112 }
113
114 // Create a land packet for a single patch.
115 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
116 {
117 int[] xPieces = new int[1];
118 int[] yPieces = new int[1];
119 xPieces[0] = patchX; // patch X dimension
120 yPieces[0] = patchY;
121
122 return CreateLandPacket(terrData, xPieces, yPieces);
123 }
124
125 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces)
126 {
127 byte landPacketType = (byte)TerrainPatch.LayerType.Land;
128 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
129 {
130 landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
131 }
132
133 return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
134 }
135
136 /// <summary>
137 /// Creates a LayerData packet for compressed land data given a full
138 /// simulator heightmap and an array of indices of patches to compress
139 /// </summary>
140 /// <param name="terrData">
141 /// Terrain data that can result in a meter square heightmap.
142 /// </param>
143 /// <param name="x">
144 /// Array of indexes in the grid of patches
145 /// for this simulator.
146 /// If creating a packet for multiple patches, there will be entries in
147 /// both the X and Y arrays for each of the patches.
148 /// For example if patches 1 and 17 are to be sent,
149 /// x[] = {1,1} and y[] = {0,1} which specifies the patches at
150 /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
151 /// </param>
152 /// <param name="y">
153 /// Array of indexes in the grid of patches.
154 /// </param>
155 /// <param name="type"></param>
156 /// <returns></returns>
157 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
158 {
159 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
160
161 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
162 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
163
164 byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
165 BitPack bitpack = new BitPack(data, 0);
166 bitpack.PackBits(header.Stride, 16);
167 bitpack.PackBits(header.PatchSize, 8);
168 bitpack.PackBits(type, 8);
169
170 for (int i = 0; i < x.Length; i++)
171 CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
172
173 bitpack.PackBits(END_OF_PATCHES, 8);
174
175 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
176 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
177
178 return layer;
179 }
180
181 // Unused: left for historical reference.
182 public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
183 {
184 TerrainPatch.Header header = PrescanPatch(patchData);
185 header.QuantWBits = 136;
186 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
187 {
188 header.PatchIDs = (y & 0xFFFF);
189 header.PatchIDs += (x << 16);
190 }
191 else
192 {
193 header.PatchIDs = (y & 0x1F);
194 header.PatchIDs += (x << 5);
195 }
196
197 // NOTE: No idea what prequant and postquant should be or what they do
198
199 int wbits;
200 int[] patch = CompressPatch(patchData, header, 10, out wbits);
201 wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
202 EncodePatch(output, patch, 0, wbits);
203 }
204
205 /// <summary>
206 /// Add a patch of terrain to a BitPacker
207 /// </summary>
208 /// <param name="output">BitPacker to write the patch to</param>
209 /// <param name="heightmap">
210 /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
211 /// </param>
212 /// <param name="patchX">
213 /// X offset of the patch to create.
214 /// </param>
215 /// <param name="patchY">
216 /// Y offset of the patch to create.
217 /// </param>
218 /// <param name="pRegionSizeX"></param>
219 /// <param name="pRegionSizeY"></param>
220 public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
221 {
222 TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
223 header.QuantWBits = 136;
224
225 // If larger than legacy region size, pack patch X and Y info differently.
226 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
227 {
228 header.PatchIDs = (patchY & 0xFFFF);
229 header.PatchIDs += (patchX << 16);
230 }
231 else
232 {
233 header.PatchIDs = (patchY & 0x1F);
234 header.PatchIDs += (patchX << 5);
235 }
236
237 // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
238 // LogHeader, patchX, patchY, header.DCOffset, header.Range);
239
240 // NOTE: No idea what prequant and postquant should be or what they do
241 int wbits;
242 int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
243 wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
244 EncodePatch(output, patch, 0, wbits);
245 }
246
247 private static TerrainPatch.Header PrescanPatch(float[] patch)
248 {
249 TerrainPatch.Header header = new TerrainPatch.Header();
250 float zmax = -99999999.0f;
251 float zmin = 99999999.0f;
252
253 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
254 {
255 float val = patch[i];
256 if (val > zmax) zmax = val;
257 if (val < zmin) zmin = val;
258 }
259
260 header.DCOffset = zmin;
261 header.Range = (int) ((zmax - zmin) + 1.0f);
262
263 return header;
264 }
265
266 // Scan the height info we're returning and return a patch packet header for this patch.
267 private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
268 {
269 TerrainPatch.Header header = new TerrainPatch.Header();
270 float zmax = -99999999.0f;
271 float zmin = 99999999.0f;
272
273 for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
274 {
275 for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
276 {
277 float val = terrData[i, j];
278 if (val > zmax) zmax = val;
279 if (val < zmin) zmin = val;
280 }
281 }
282
283 header.DCOffset = zmin;
284 header.Range = (int)((zmax - zmin) + 1.0f);
285
286 return header;
287 }
288
289 public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
290 {
291 TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
292
293 // Quantized word bits
294 if (header.QuantWBits == END_OF_PATCHES)
295 return header;
296
297 // DC offset
298 header.DCOffset = bitpack.UnpackFloat();
299
300 // Range
301 header.Range = bitpack.UnpackBits(16);
302
303 // Patch IDs (10 bits)
304 header.PatchIDs = bitpack.UnpackBits(10);
305
306 // Word bits
307 header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
308
309 return header;
310 }
311
312 private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
313 uint pRegionSizeY, int wbits)
314 {
315 /*
316 int temp;
317 int wbits = (header.QuantWBits & 0x0f) + 2;
318 uint maxWbits = (uint)wbits + 5;
319 uint minWbits = ((uint)wbits >> 1);
320 int wbitsMaxValue;
321 */
322 // goal is to determ minimum number of bits to use so all data fits
323 /*
324 wbits = (int)minWbits;
325 wbitsMaxValue = (1 << wbits);
326
327 for (int i = 0; i < patch.Length; i++)
328 {
329 temp = patch[i];
330 if (temp != 0)
331 {
332 // Get the absolute value
333 if (temp < 0) temp *= -1;
334
335 no coments..
336
337 for (int j = (int)maxWbits; j > (int)minWbits; j--)
338 {
339 if ((temp & (1 << j)) != 0)
340 {
341 if (j > wbits) wbits = j;
342 break;
343 }
344 }
345
346 while (temp > wbitsMaxValue)
347 {
348 wbits++;
349 if (wbits == maxWbits)
350 goto Done;
351 wbitsMaxValue = 1 << wbits;
352 }
353 }
354 }
355
356 Done:
357
358 // wbits += 1;
359 */
360 // better check
361 if (wbits > 17)
362 wbits = 16;
363 else if (wbits < 3)
364 wbits = 3;
365
366 header.QuantWBits &= 0xf0;
367
368 header.QuantWBits |= (wbits - 2);
369
370 output.PackBits(header.QuantWBits, 8);
371 output.PackFloat(header.DCOffset);
372 output.PackBits(header.Range, 16);
373 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
374 output.PackBits(header.PatchIDs, 32);
375 else
376 output.PackBits(header.PatchIDs, 10);
377
378 return wbits;
379 }
380
381 private static void IDCTColumn16(float[] linein, float[] lineout, int column)
382 {
383 for (int n = 0; n < Constants.TerrainPatchSize; n++)
384 {
385 float total = OO_SQRT2*linein[column];
386
387 for (int u = 1; u < Constants.TerrainPatchSize; u++)
388 {
389 int usize = u*Constants.TerrainPatchSize;
390 total += linein[usize + column]*CosineTable16[usize + n];
391 }
392
393 lineout[Constants.TerrainPatchSize*n + column] = total;
394 }
395 }
396
397 private static void IDCTLine16(float[] linein, float[] lineout, int line)
398 {
399 const float oosob = 2.0f/Constants.TerrainPatchSize;
400 int lineSize = line*Constants.TerrainPatchSize;
401
402 for (int n = 0; n < Constants.TerrainPatchSize; n++)
403 {
404 float total = OO_SQRT2*linein[lineSize];
405
406 for (int u = 1; u < Constants.TerrainPatchSize; u++)
407 {
408 total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
409 }
410
411 lineout[lineSize + n] = total*oosob;
412 }
413 }
414
415/*
416 private static void DCTLine16(float[] linein, float[] lineout, int line)
417 {
418 float total = 0.0f;
419 int lineSize = line * Constants.TerrainPatchSize;
420
421 for (int n = 0; n < Constants.TerrainPatchSize; n++)
422 {
423 total += linein[lineSize + n];
424 }
425
426 lineout[lineSize] = OO_SQRT2 * total;
427
428 int uptr = 0;
429 for (int u = 1; u < Constants.TerrainPatchSize; u++)
430 {
431 total = 0.0f;
432 uptr += Constants.TerrainPatchSize;
433
434 for (int n = 0; n < Constants.TerrainPatchSize; n++)
435 {
436 total += linein[lineSize + n] * CosineTable16[uptr + n];
437 }
438
439 lineout[lineSize + u] = total;
440 }
441 }
442*/
443
444 private static void DCTLine16(float[] linein, float[] lineout, int line)
445 {
446 // outputs transpose data (lines exchanged with coluns )
447 // so to save a bit of cpu when doing coluns
448 float total = 0.0f;
449 int lineSize = line*Constants.TerrainPatchSize;
450
451 for (int n = 0; n < Constants.TerrainPatchSize; n++)
452 {
453 total += linein[lineSize + n];
454 }
455
456 lineout[line] = OO_SQRT2*total;
457
458 for (int u = Constants.TerrainPatchSize;
459 u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
460 u += Constants.TerrainPatchSize)
461 {
462 total = 0.0f;
463 for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
464 {
465 total += linein[ptrn]*CosineTable16[ptru];
466 }
467
468 lineout[line + u] = total;
469 }
470 }
471
472
473 /*
474 private static void DCTColumn16(float[] linein, int[] lineout, int column)
475 {
476 float total = 0.0f;
477 // const float oosob = 2.0f / Constants.TerrainPatchSize;
478
479 for (int n = 0; n < Constants.TerrainPatchSize; n++)
480 {
481 total += linein[Constants.TerrainPatchSize * n + column];
482 }
483
484 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
485 lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
486
487 for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
488 {
489 total = 0.0f;
490
491 for (int n = 0; n < Constants.TerrainPatchSize; n++)
492 {
493 total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
494 }
495
496 // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
497 lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
498 }
499 }
500
501 private static void DCTColumn16(float[] linein, int[] lineout, int column)
502 {
503 // input columns are in fact stored in lines now
504
505 float total = 0.0f;
506// const float oosob = 2.0f / Constants.TerrainPatchSize;
507 int inlinesptr = Constants.TerrainPatchSize*column;
508
509 for (int n = 0; n < Constants.TerrainPatchSize; n++)
510 {
511 total += linein[inlinesptr + n];
512 }
513
514 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
515 lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
516
517 for (int uptr = Constants.TerrainPatchSize;
518 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
519 uptr += Constants.TerrainPatchSize)
520 {
521 total = 0.0f;
522
523 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
524 {
525 total += linein[n]*CosineTable16[ptru];
526 }
527
528// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
529 lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
530 }
531 }
532 */
533
534 private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
535 {
536 // input columns are in fact stored in lines now
537
538 bool dowbits = wbits != maxwbits;
539 int wbitsMaxValue = 1 << wbits;
540
541 float total = 0.0f;
542 // const float oosob = 2.0f / Constants.TerrainPatchSize;
543 int inlinesptr = Constants.TerrainPatchSize*column;
544
545 for (int n = 0; n < Constants.TerrainPatchSize; n++)
546 {
547 total += linein[inlinesptr + n];
548 }
549
550 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
551 int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
552 lineout[CopyMatrix16[column]] = tmp;
553
554 if (dowbits)
555 {
556 if (tmp < 0) tmp *= -1;
557 while (tmp > wbitsMaxValue)
558 {
559 wbits++;
560 wbitsMaxValue = 1 << wbits;
561 if (wbits == maxwbits)
562 {
563 dowbits = false;
564 break;
565 }
566 }
567 }
568
569 for (int uptr = Constants.TerrainPatchSize;
570 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
571 uptr += Constants.TerrainPatchSize)
572 {
573 total = 0.0f;
574
575 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
576 {
577 total += linein[n]*CosineTable16[ptru];
578 }
579
580 tmp = (int) (total*QuantizeTable16[uptr + column]);
581 lineout[CopyMatrix16[uptr + column]] = tmp;
582
583 if (dowbits)
584 {
585 if (tmp < 0) tmp *= -1;
586 while (tmp > wbitsMaxValue)
587 {
588 wbits++;
589 wbitsMaxValue = 1 << wbits;
590 if (wbits == maxwbits)
591 {
592 dowbits = false;
593 break;
594 }
595 }
596 }
597 }
598 return wbits;
599 }
600
601 public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
602 {
603 for (int n = 0; n < size*size; n++)
604 {
605 // ?
606 int temp = bitpack.UnpackBits(1);
607 if (temp != 0)
608 {
609 // Value or EOB
610 temp = bitpack.UnpackBits(1);
611 if (temp != 0)
612 {
613 // Value
614 temp = bitpack.UnpackBits(1);
615 if (temp != 0)
616 {
617 // Negative
618 temp = bitpack.UnpackBits((int) header.WordBits);
619 patches[n] = temp*-1;
620 }
621 else
622 {
623 // Positive
624 temp = bitpack.UnpackBits((int) header.WordBits);
625 patches[n] = temp;
626 }
627 }
628 else
629 {
630 // Set the rest to zero
631 // TODO: This might not be necessary
632 for (int o = n; o < size*size; o++)
633 {
634 patches[o] = 0;
635 }
636 break;
637 }
638 }
639 else
640 {
641 patches[n] = 0;
642 }
643 }
644 }
645
646 private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
647 {
648 int maxwbitssize = (1 << wbits) - 1;
649
650 if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
651 {
652 Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
653 return;
654 }
655
656 if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
657
658 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
659 {
660 int temp = patch[i];
661
662 if (temp == 0)
663 {
664 bool eob = true;
665
666 for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
667 {
668 if (patch[j] != 0)
669 {
670 eob = false;
671 break;
672 }
673 }
674
675 if (eob)
676 {
677 output.PackBits(ZERO_EOB, 2);
678 return;
679 }
680 output.PackBits(ZERO_CODE, 1);
681 }
682 else
683 {
684 if (temp < 0)
685 {
686 temp *= -1;
687
688 if (temp > maxwbitssize) temp = maxwbitssize;
689
690 output.PackBits(NEGATIVE_VALUE, 3);
691 output.PackBits(temp, wbits);
692 }
693 else
694 {
695 if (temp > maxwbitssize) temp = maxwbitssize;
696
697 output.PackBits(POSITIVE_VALUE, 3);
698 output.PackBits(temp, wbits);
699 }
700 }
701 }
702 }
703
704 public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
705 {
706 float[] block = new float[group.PatchSize*group.PatchSize];
707 float[] output = new float[group.PatchSize*group.PatchSize];
708 int prequant = (header.QuantWBits >> 4) + 2;
709 int quantize = 1 << prequant;
710 float ooq = 1.0f/quantize;
711 float mult = ooq*header.Range;
712 float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
713
714 if (group.PatchSize == Constants.TerrainPatchSize)
715 {
716 for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
717 {
718 block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
719 }
720
721 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
722
723 for (int o = 0; o < Constants.TerrainPatchSize; o++)
724 IDCTColumn16(block, ftemp, o);
725 for (int o = 0; o < Constants.TerrainPatchSize; o++)
726 IDCTLine16(ftemp, block, o);
727 }
728 else
729 {
730 for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
731 {
732 block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
733 }
734
735 Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
736 }
737
738 for (int j = 0; j < block.Length; j++)
739 {
740 output[j] = block[j]*mult + addval;
741 }
742
743 return output;
744 }
745
746 private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
747 {
748 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
749 int wordsize = (prequant - 2) & 0x0f;
750 float oozrange = 1.0f/header.Range;
751 float range = (1 << prequant);
752 float premult = oozrange*range;
753 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
754
755 header.QuantWBits = wordsize;
756 header.QuantWBits |= wordsize << 4;
757
758 int k = 0;
759 for (int j = 0; j < Constants.TerrainPatchSize; j++)
760 {
761 for (int i = 0; i < Constants.TerrainPatchSize; i++)
762 block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
763 }
764
765 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
766 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
767
768
769 int maxWbits = prequant + 5;
770 wbits = (prequant >> 1);
771
772 for (int o = 0; o < Constants.TerrainPatchSize; o++)
773 DCTLine16(block, ftemp, o);
774 for (int o = 0; o < Constants.TerrainPatchSize; o++)
775 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
776
777 return itemp;
778 }
779
780 private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
781 {
782 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
783 float oozrange = 1.0f/header.Range;
784 float range = (1 << prequant);
785 float premult = oozrange*range;
786 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
787 int wordsize = (prequant - 2) & 0x0f;
788
789 header.QuantWBits = wordsize;
790 header.QuantWBits |= wordsize << 4;
791
792 int k = 0;
793 for (int j = 0; j < Constants.TerrainPatchSize; j++)
794 {
795 for (int i = 0; i < Constants.TerrainPatchSize; i++)
796 block[k++] = patchData[j, i]*premult - sub;
797 }
798
799 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
800 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
801
802 int maxWbits = prequant + 5;
803 wbits = (prequant >> 1);
804
805 for (int o = 0; o < Constants.TerrainPatchSize; o++)
806 DCTLine16(block, ftemp, o);
807 for (int o = 0; o < Constants.TerrainPatchSize; o++)
808 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
809
810 return itemp;
811 }
812
813 private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
814 int prequant, out int wbits)
815 {
816 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
817 int wordsize = prequant;
818 float oozrange = 1.0f/header.Range;
819 float range = (1 << prequant);
820 float premult = oozrange*range;
821 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
822
823 header.QuantWBits = wordsize - 2;
824 header.QuantWBits |= (prequant - 2) << 4;
825
826 int k = 0;
827
828 int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
829 (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
830 yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
831
832 int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
833 (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
834 xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
835
836 for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
837 {
838 for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
839 {
840 block[k++] = terrData[xx, yy] * premult - sub;
841 }
842 }
843
844 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
845 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
846
847 int maxWbits = prequant + 5;
848 wbits = (prequant >> 1);
849
850 for (int o = 0; o < Constants.TerrainPatchSize; o++)
851 DCTLine16(block, ftemp, o);
852 for (int o = 0; o < Constants.TerrainPatchSize; o++)
853 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
854
855 return itemp;
856 }
857
858 #region Initialization
859
860 private static void BuildDequantizeTable16()
861 {
862 for (int j = 0; j < Constants.TerrainPatchSize; j++)
863 {
864 for (int i = 0; i < Constants.TerrainPatchSize; i++)
865 {
866 DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
867 }
868 }
869 }
870
871 private static void BuildQuantizeTable16()
872 {
873 const float oosob = 2.0f/Constants.TerrainPatchSize;
874 for (int j = 0; j < Constants.TerrainPatchSize; j++)
875 {
876 for (int i = 0; i < Constants.TerrainPatchSize; i++)
877 {
878// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
879 QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
880 }
881 }
882 }
883
884 private static void SetupCosines16()
885 {
886 const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
887
888 for (int u = 0; u < Constants.TerrainPatchSize; u++)
889 {
890 for (int n = 0; n < Constants.TerrainPatchSize; n++)
891 {
892 CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
893 }
894 }
895 }
896
897 private static void BuildCopyMatrix16()
898 {
899 bool diag = false;
900 bool right = true;
901 int i = 0;
902 int j = 0;
903 int count = 0;
904
905 while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
906 {
907 CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
908
909 if (!diag)
910 {
911 if (right)
912 {
913 if (i < Constants.TerrainPatchSize - 1) i++;
914 else j++;
915
916 right = false;
917 diag = true;
918 }
919 else
920 {
921 if (j < Constants.TerrainPatchSize - 1) j++;
922 else i++;
923
924 right = true;
925 diag = true;
926 }
927 }
928 else
929 {
930 if (right)
931 {
932 i++;
933 j--;
934 if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
935 }
936 else
937 {
938 i--;
939 j++;
940 if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
941 }
942 }
943 }
944 }
945
946 #endregion Initialization
947 }
948}