diff options
author | UbitUmarov | 2015-08-19 08:48:50 +0100 |
---|---|---|
committer | UbitUmarov | 2015-08-19 08:48:50 +0100 |
commit | 0b105da626ae8c2fb519a817b827f90534ed7d08 (patch) | |
tree | 509e6d091fb12f38fd09528335e51aeedbe59c08 /OpenSim/Region/Framework/Scenes | |
parent | Merge branch 'master' into ubitworkmaster (diff) | |
parent | varregion: update MapImageServiceModule to upload multiple map tiles for larg... (diff) | |
download | opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.zip opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.tar.gz opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.tar.bz2 opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.tar.xz |
Merge branch 'mbworkvar2' into ubitvar
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 11 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 362 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs | 9 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 12 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 5 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 79 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 352 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/TerrainCompressor.cs | 948 |
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 | ||
28 | using OpenSim.Framework; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | using System; | 28 | using System; |
29 | using System.IO; | ||
31 | using System.Text; | 30 | using System.Text; |
31 | using System.Reflection; | ||
32 | using System.Xml; | 32 | using System.Xml; |
33 | using System.IO; | ||
34 | using System.Xml.Serialization; | 33 | using System.Xml.Serialization; |
35 | 34 | ||
35 | using OpenSim.Data; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | using log4net; | ||
42 | |||
36 | namespace OpenSim.Region.Framework.Scenes | 43 | namespace 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 | |||
32 | using System; | ||
33 | using System.Reflection; | ||
34 | |||
35 | using log4net; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | |||
41 | using OpenMetaverse; | ||
42 | using OpenMetaverse.Packets; | ||
43 | |||
44 | namespace 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 | } | ||