aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs119
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs54
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs74
6 files changed, 267 insertions, 42 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index a30d8eb..974fd57 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -33,6 +33,7 @@ using System.Threading;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Capabilities; 34using OpenSim.Framework.Capabilities;
35using OpenSim.Framework.Client; 35using OpenSim.Framework.Client;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
@@ -77,6 +78,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
77 /// </remarks> 78 /// </remarks>
78 public bool DisableInterRegionTeleportCancellation { get; set; } 79 public bool DisableInterRegionTeleportCancellation { get; set; }
79 80
81 /// <summary>
82 /// Number of times inter-region teleport was attempted.
83 /// </summary>
84 private Stat m_interRegionTeleportAttempts;
85
86 /// <summary>
87 /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
88 /// </summary>
89 private Stat m_interRegionTeleportAborts;
90
91 /// <summary>
92 /// Number of times inter-region teleport was successfully cancelled by the client.
93 /// </summary>
94 private Stat m_interRegionTeleportCancels;
95
96 /// <summary>
97 /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
98 /// connect with destination region).
99 /// </summary>
100 /// <remarks>
101 /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
102 /// destination simulator is unknown.
103 /// </remarks>
104 private Stat m_interRegionTeleportFailures;
105
80 protected bool m_Enabled = false; 106 protected bool m_Enabled = false;
81 107
82 public Scene Scene { get; private set; } 108 public Scene Scene { get; private set; }
@@ -156,6 +182,60 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
156 182
157 Scene = scene; 183 Scene = scene;
158 184
185 m_interRegionTeleportAttempts =
186 new Stat(
187 "InterRegionTeleportAttempts",
188 "Number of inter-region teleports attempted.",
189 "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
190 + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
191 "",
192 "entitytransfer",
193 Scene.Name,
194 StatType.Push,
195 null,
196 StatVerbosity.Debug);
197
198 m_interRegionTeleportAborts =
199 new Stat(
200 "InterRegionTeleportAborts",
201 "Number of inter-region teleports aborted due to client actions.",
202 "The chief action is simultaneous logout whilst teleporting.",
203 "",
204 "entitytransfer",
205 Scene.Name,
206 StatType.Push,
207 null,
208 StatVerbosity.Debug);
209
210 m_interRegionTeleportCancels =
211 new Stat(
212 "InterRegionTeleportCancels",
213 "Number of inter-region teleports cancelled by the client.",
214 null,
215 "",
216 "entitytransfer",
217 Scene.Name,
218 StatType.Push,
219 null,
220 StatVerbosity.Debug);
221
222 m_interRegionTeleportFailures =
223 new Stat(
224 "InterRegionTeleportFailures",
225 "Number of inter-region teleports that failed due to server/client/network issues.",
226 "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
227 "",
228 "entitytransfer",
229 Scene.Name,
230 StatType.Push,
231 null,
232 StatVerbosity.Debug);
233
234 StatsManager.RegisterStat(m_interRegionTeleportAttempts);
235 StatsManager.RegisterStat(m_interRegionTeleportAborts);
236 StatsManager.RegisterStat(m_interRegionTeleportCancels);
237 StatsManager.RegisterStat(m_interRegionTeleportFailures);
238
159 scene.RegisterModuleInterface<IEntityTransferModule>(this); 239 scene.RegisterModuleInterface<IEntityTransferModule>(this);
160 scene.EventManager.OnNewClient += OnNewClient; 240 scene.EventManager.OnNewClient += OnNewClient;
161 } 241 }
@@ -173,7 +253,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
173 253
174 public virtual void Close() {} 254 public virtual void Close() {}
175 255
176 public virtual void RemoveRegion(Scene scene) {} 256 public virtual void RemoveRegion(Scene scene)
257 {
258 StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
259 StatsManager.DeregisterStat(m_interRegionTeleportAborts);
260 StatsManager.DeregisterStat(m_interRegionTeleportCancels);
261 StatsManager.DeregisterStat(m_interRegionTeleportFailures);
262 }
177 263
178 public virtual void RegionLoaded(Scene scene) 264 public virtual void RegionLoaded(Scene scene)
179 { 265 {
@@ -548,6 +634,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
548 return; 634 return;
549 } 635 }
550 636
637 // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
638 // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
639 // as server attempts.
640 m_interRegionTeleportAttempts.Value++;
641
551 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 642 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
552 643
553 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 644 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
@@ -600,6 +691,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
600 bool logout = false; 691 bool logout = false;
601 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 692 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
602 { 693 {
694 m_interRegionTeleportFailures.Value++;
695
603 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 696 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
604 697
605 m_log.DebugFormat( 698 m_log.DebugFormat(
@@ -611,6 +704,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
611 704
612 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) 705 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
613 { 706 {
707 m_interRegionTeleportCancels.Value++;
708
614 m_log.DebugFormat( 709 m_log.DebugFormat(
615 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", 710 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
616 sp.Name, finalDestination.RegionName, sp.Scene.Name); 711 sp.Name, finalDestination.RegionName, sp.Scene.Name);
@@ -619,6 +714,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
619 } 714 }
620 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) 715 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
621 { 716 {
717 m_interRegionTeleportAborts.Value++;
718
622 m_log.DebugFormat( 719 m_log.DebugFormat(
623 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", 720 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
624 sp.Name, finalDestination.RegionName, sp.Scene.Name); 721 sp.Name, finalDestination.RegionName, sp.Scene.Name);
@@ -688,6 +785,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
688 // establish th econnection to the destination which makes it return true. 785 // establish th econnection to the destination which makes it return true.
689 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) 786 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
690 { 787 {
788 m_interRegionTeleportAborts.Value++;
789
691 m_log.DebugFormat( 790 m_log.DebugFormat(
692 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", 791 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
693 sp.Name, finalDestination.RegionName, sp.Scene.Name); 792 sp.Name, finalDestination.RegionName, sp.Scene.Name);
@@ -703,6 +802,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
703 { 802 {
704 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) 803 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
705 { 804 {
805 m_interRegionTeleportAborts.Value++;
806
706 m_log.DebugFormat( 807 m_log.DebugFormat(
707 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", 808 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
708 sp.Name, finalDestination.RegionName, sp.Scene.Name); 809 sp.Name, finalDestination.RegionName, sp.Scene.Name);
@@ -720,6 +821,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
720 821
721 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) 822 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
722 { 823 {
824 m_interRegionTeleportCancels.Value++;
825
723 m_log.DebugFormat( 826 m_log.DebugFormat(
724 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", 827 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
725 sp.Name, finalDestination.RegionName, sp.Scene.Name); 828 sp.Name, finalDestination.RegionName, sp.Scene.Name);
@@ -755,6 +858,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
755 { 858 {
756 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) 859 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
757 { 860 {
861 m_interRegionTeleportAborts.Value++;
862
758 m_log.DebugFormat( 863 m_log.DebugFormat(
759 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", 864 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
760 sp.Name, finalDestination.RegionName, sp.Scene.Name); 865 sp.Name, finalDestination.RegionName, sp.Scene.Name);
@@ -767,6 +872,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
767 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 872 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
768 873
769 Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion."); 874 Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
875
770 return; 876 return;
771 } 877 }
772 878
@@ -808,15 +914,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
808 // now we have a child agent in this region. 914 // now we have a child agent in this region.
809 sp.Reset(); 915 sp.Reset();
810 } 916 }
811
812 // Commented pending deletion since this method no longer appears to do anything at all
813// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
814// if (sp.Scene.NeedSceneCacheClear(sp.UUID))
815// {
816// m_log.DebugFormat(
817// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
818// sp.UUID);
819// }
820 } 917 }
821 918
822 /// <summary> 919 /// <summary>
@@ -852,6 +949,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
852 { 949 {
853 CleanupFailedInterRegionTeleport(sp, finalDestination); 950 CleanupFailedInterRegionTeleport(sp, finalDestination);
854 951
952 m_interRegionTeleportFailures.Value++;
953
855 sp.ControllingClient.SendTeleportFailed( 954 sp.ControllingClient.SendTeleportFailed(
856 string.Format( 955 string.Format(
857 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason)); 956 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5549984..65df741 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -321,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
321 } 321 }
322 } 322 }
323 323
324 internal void ProcessTypeChange(Vehicle pType) 324 public void ProcessTypeChange(Vehicle pType)
325 { 325 {
326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 326 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
327 // Set Defaults For Type 327 // Set Defaults For Type
@@ -1301,14 +1301,52 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. 1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1302 public void ComputeAngularVerticalAttraction() 1302 public void ComputeAngularVerticalAttraction()
1303 { 1303 {
1304
1304 // If vertical attaction timescale is reasonable 1305 // If vertical attaction timescale is reasonable
1305 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1306 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1306 { 1307 {
1308 // Possible solution derived from a discussion at:
1309 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1310
1311 // Create a rotation that is only the vehicle's rotation around Z
1312 Vector3 currentEuler = Vector3.Zero;
1313 VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
1314 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
1315
1316 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1317 Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1318 // Compute the angle between those to vectors.
1319 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1320 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1321
1322 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1323 // TODO: add 'efficiency'.
1324 differenceAngle /= m_verticalAttractionTimescale;
1325
1326 // Create the quaterian representing the correction angle
1327 Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
1328
1329 // Turn that quaternion into Euler values to make it into velocities to apply.
1330 Vector3 vertContributionV = Vector3.Zero;
1331 correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
1332 vertContributionV *= -1f;
1333
1334 VehicleRotationalVelocity += vertContributionV;
1335
1336 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1337 Prim.LocalID,
1338 differenceAxis,
1339 differenceAngle,
1340 correctionRotation,
1341 vertContributionV);
1342
1343 // ===================================================================
1344 /*
1307 Vector3 vertContributionV = Vector3.Zero; 1345 Vector3 vertContributionV = Vector3.Zero;
1308 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG 1346 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1309 1347
1310 // Take a vector pointing up and convert it from world to vehicle relative coords. 1348 // Take a vector pointing up and convert it from world to vehicle relative coords.
1311 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; 1349 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1312 1350
1313 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) 1351 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1314 // is now: 1352 // is now:
@@ -1334,13 +1372,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1334 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. 1372 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1335 // Correction happens over a number of seconds. 1373 // Correction happens over a number of seconds.
1336 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG 1374 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1375
1376 // The correction happens over the user's time period
1337 vertContributionV /= m_verticalAttractionTimescale; 1377 vertContributionV /= m_verticalAttractionTimescale;
1338 1378
1339 VehicleRotationalVelocity += vertContributionV; 1379 // Rotate the vehicle rotation to the world coordinates.
1380 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1340 1381
1341 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", 1382 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1342 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, 1383 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1343 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); 1384 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1385 */
1344 } 1386 }
1345 } 1387 }
1346 1388
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 4d89a88..f3454c8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -142,6 +142,14 @@ public static class BSParam
142 public static float VehicleAngularBankingTimescaleFudge { get; private set; } 142 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
143 public static bool VehicleDebuggingEnabled { get; private set; } 143 public static bool VehicleDebuggingEnabled { get; private set; }
144 144
145 // Convex Hulls
146 public static int CSHullMaxDepthSplit { get; private set; }
147 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
148 public static float CSHullConcavityThresholdPercent { get; private set; }
149 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
150 public static int CSHullMaxVertices { get; private set; }
151 public static float CSHullMaxSkinWidth { get; private set; }
152
145 // Linkset implementation parameters 153 // Linkset implementation parameters
146 public static float LinksetImplementation { get; private set; } 154 public static float LinksetImplementation { get; private set; }
147 public static bool LinkConstraintUseFrameOffset { get; private set; } 155 public static bool LinkConstraintUseFrameOffset { get; private set; }
@@ -195,10 +203,10 @@ public static class BSParam
195 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj); 203 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
196 public sealed class ParameterDefn<T> : ParameterDefnBase 204 public sealed class ParameterDefn<T> : ParameterDefnBase
197 { 205 {
198 T defaultValue; 206 private T defaultValue;
199 PSetValue<T> setter; 207 private PSetValue<T> setter;
200 PGetValue<T> getter; 208 private PGetValue<T> getter;
201 PSetOnObject<T> objectSet; 209 private PSetOnObject<T> objectSet;
202 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter) 210 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
203 : base(pName, pDesc) 211 : base(pName, pDesc)
204 { 212 {
@@ -215,13 +223,23 @@ public static class BSParam
215 getter = pGetter; 223 getter = pGetter;
216 objectSet = pObjSetter; 224 objectSet = pObjSetter;
217 } 225 }
226 /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work
227 public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc)
228 : base(pName, pDesc)
229 {
230 defaultValue = pDefault;
231 setter = (s, v) => { loc = v; };
232 getter = (s) => { return loc; };
233 objectSet = null;
234 }
235 */
218 public override void AssignDefault(BSScene s) 236 public override void AssignDefault(BSScene s)
219 { 237 {
220 setter(s, defaultValue); 238 setter(s, defaultValue);
221 } 239 }
222 public override string GetValue(BSScene s) 240 public override string GetValue(BSScene s)
223 { 241 {
224 return String.Format("{0}", getter(s)); 242 return getter(s).ToString();
225 } 243 }
226 public override void SetValue(BSScene s, string valAsString) 244 public override void SetValue(BSScene s, string valAsString)
227 { 245 {
@@ -244,6 +262,7 @@ public static class BSParam
244 try 262 try
245 { 263 {
246 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); 264 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
265 // Store the parsed value
247 setter(s, setValue); 266 setter(s, setValue);
248 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); 267 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
249 } 268 }
@@ -623,6 +642,31 @@ public static class BSParam
623 (s) => { return GlobalContactBreakingThreshold; }, 642 (s) => { return GlobalContactBreakingThreshold; },
624 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), 643 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
625 644
645 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
646 7,
647 (s) => { return CSHullMaxDepthSplit; },
648 (s,v) => { CSHullMaxDepthSplit = v; } ),
649 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
650 2,
651 (s) => { return CSHullMaxDepthSplitForSimpleShapes; },
652 (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
653 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
654 5f,
655 (s) => { return CSHullConcavityThresholdPercent; },
656 (s,v) => { CSHullConcavityThresholdPercent = v; } ),
657 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
658 5f,
659 (s) => { return CSHullVolumeConservationThresholdPercent; },
660 (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
661 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
662 32,
663 (s) => { return CSHullMaxVertices; },
664 (s,v) => { CSHullMaxVertices = v; } ),
665 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
666 0,
667 (s) => { return CSHullMaxSkinWidth; },
668 (s,v) => { CSHullMaxSkinWidth = v; } ),
669
626 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", 670 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
627 (float)BSLinkset.LinksetImplementation.Compound, 671 (float)BSLinkset.LinksetImplementation.Compound,
628 (s) => { return LinksetImplementation; }, 672 (s) => { return LinksetImplementation; },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f953c1e..6bb88c7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -86,7 +86,7 @@ public abstract class BSPhysObject : PhysicsActor
86 PhysBody = new BulletBody(localID); 86 PhysBody = new BulletBody(localID);
87 PhysShape = new BulletShape(); 87 PhysShape = new BulletShape();
88 88
89 LastAssetBuildFailed = false; 89 PrimAssetState = PrimAssetCondition.Unknown;
90 90
91 // Default material type. Also sets Friction, Restitution and Density. 91 // Default material type. Also sets Friction, Restitution and Density.
92 SetMaterial((int)MaterialAttributes.Material.Wood); 92 SetMaterial((int)MaterialAttributes.Material.Wood);
@@ -133,9 +133,13 @@ public abstract class BSPhysObject : PhysicsActor
133 // Reference to the physical shape (btCollisionShape) of this object 133 // Reference to the physical shape (btCollisionShape) of this object
134 public BulletShape PhysShape; 134 public BulletShape PhysShape;
135 135
136 // 'true' if the mesh's underlying asset failed to build. 136 // The physical representation of the prim might require an asset fetch.
137 // This will keep us from looping after the first time the build failed. 137 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
138 public bool LastAssetBuildFailed { get; set; } 138 public enum PrimAssetCondition
139 {
140 Unknown, Waiting, Failed, Fetched
141 }
142 public PrimAssetCondition PrimAssetState { get; set; }
139 143
140 // The objects base shape information. Null if not a prim type shape. 144 // The objects base shape information. Null if not a prim type shape.
141 public PrimitiveBaseShape BaseShape { get; protected set; } 145 public PrimitiveBaseShape BaseShape { get; protected set; }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2cbbe9a..6a5461a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -155,7 +155,7 @@ public class BSPrim : BSPhysObject
155 public override PrimitiveBaseShape Shape { 155 public override PrimitiveBaseShape Shape {
156 set { 156 set {
157 BaseShape = value; 157 BaseShape = value;
158 LastAssetBuildFailed = false; 158 PrimAssetState = PrimAssetCondition.Unknown;
159 ForceBodyShapeRebuild(false); 159 ForceBodyShapeRebuild(false);
160 } 160 }
161 } 161 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 05c147d..7609578 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -447,17 +447,10 @@ public sealed class BSShapeCollection : IDisposable
447 447
448 // If the prim attributes are simple, this could be a simple Bullet native shape 448 // If the prim attributes are simple, this could be a simple Bullet native shape
449 if (!haveShape 449 if (!haveShape
450 && nativeShapePossible
450 && pbs != null 451 && pbs != null
451 && !pbs.SculptEntry 452 && !pbs.SculptEntry
452 && nativeShapePossible 453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
454 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
455 && pbs.ProfileHollow == 0
456 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
457 && pbs.PathBegin == 0 && pbs.PathEnd == 0
458 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
459 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
460 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
461 { 454 {
462 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
463 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
@@ -508,6 +501,18 @@ public sealed class BSShapeCollection : IDisposable
508 return ret; 501 return ret;
509 } 502 }
510 503
504 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0
509 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
510 && pbs.PathBegin == 0 && pbs.PathEnd == 0
511 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
512 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
513 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
514 }
515
511 // return 'true' if the prim's shape was changed. 516 // return 'true' if the prim's shape was changed.
512 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
513 { 518 {
@@ -518,7 +523,7 @@ public sealed class BSShapeCollection : IDisposable
518 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
519 { 524 {
520 // Update prim.BSShape to reference a hull of this shape. 525 // Update prim.BSShape to reference a hull of this shape.
521 ret = GetReferenceToHull(prim,shapeCallback); 526 ret = GetReferenceToHull(prim, shapeCallback);
522 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
523 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
524 } 529 }
@@ -699,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
699 704
700 // See that hull shape exists in the physical world and update prim.BSShape. 705 // See that hull shape exists in the physical world and update prim.BSShape.
701 // We could be creating the hull because scale changed or whatever. 706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
702 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
703 { 709 {
704 BulletShape newShape; 710 BulletShape newShape;
@@ -717,6 +723,7 @@ public sealed class BSShapeCollection : IDisposable
717 DereferenceShape(prim.PhysShape, shapeCallback); 723 DereferenceShape(prim.PhysShape, shapeCallback);
718 724
719 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); 725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
720 newShape = VerifyMeshCreated(newShape, prim); 727 newShape = VerifyMeshCreated(newShape, prim);
721 728
722 ReferenceShape(newShape); 729 ReferenceShape(newShape);
@@ -735,13 +742,13 @@ public sealed class BSShapeCollection : IDisposable
735 HullDesc hullDesc; 742 HullDesc hullDesc;
736 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
737 { 744 {
738 // If the hull shape already is created, just use it. 745 // If the hull shape already has been created, just use the one shared instance.
739 newShape = hullDesc.shape.Clone(); 746 newShape = hullDesc.shape.Clone();
740 } 747 }
741 else 748 else
742 { 749 {
743 // Build a new hull in the physical world 750 // Build a new hull in the physical world.
744 // Pass true for physicalness as this creates some sort of bounding box which we don't need 751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
745 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); 752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
746 if (meshData != null) 753 if (meshData != null)
747 { 754 {
@@ -761,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
761 convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); 768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
762 } 769 }
763 770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
764 // setup and do convex hull conversion 783 // setup and do convex hull conversion
765 m_hulls = new List<ConvexResult>(); 784 m_hulls = new List<ConvexResult>();
766 DecompDesc dcomp = new DecompDesc(); 785 DecompDesc dcomp = new DecompDesc();
767 dcomp.mIndices = convIndices; 786 dcomp.mIndices = convIndices;
768 dcomp.mVertices = convVertices; 787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
769 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); 793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
770 // create the hull into the _hulls variable 794 // create the hull into the _hulls variable
771 convexBuilder.process(dcomp); 795 convexBuilder.process(dcomp);
772 796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
773 // Convert the vertices and indices for passing to unmanaged. 800 // Convert the vertices and indices for passing to unmanaged.
774 // The hull information is passed as a large floating point array. 801 // The hull information is passed as a large floating point array.
775 // The format is: 802 // The format is:
@@ -905,11 +932,15 @@ public sealed class BSShapeCollection : IDisposable
905 return newShape; 932 return newShape;
906 933
907 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 934 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
908 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) 935 if (prim.BaseShape.SculptEntry
936 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
937 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
938 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
939 )
909 { 940 {
910 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed); 941 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
911 // This will prevent looping through this code as we keep trying to get the failed shape 942 // Multiple requestors will know we're waiting for this asset
912 prim.LastAssetBuildFailed = true; 943 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
913 944
914 BSPhysObject xprim = prim; 945 BSPhysObject xprim = prim;
915 Util.FireAndForget(delegate 946 Util.FireAndForget(delegate
@@ -920,7 +951,7 @@ public sealed class BSShapeCollection : IDisposable
920 BSPhysObject yprim = xprim; // probably not necessary, but, just in case. 951 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
921 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) 952 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
922 { 953 {
923 bool assetFound = false; // DEBUG DEBUG 954 bool assetFound = false;
924 string mismatchIDs = String.Empty; // DEBUG DEBUG 955 string mismatchIDs = String.Empty; // DEBUG DEBUG
925 if (asset != null && yprim.BaseShape.SculptEntry) 956 if (asset != null && yprim.BaseShape.SculptEntry)
926 { 957 {
@@ -938,6 +969,10 @@ public sealed class BSShapeCollection : IDisposable
938 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; 969 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
939 } 970 }
940 } 971 }
972 if (assetFound)
973 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
974 else
975 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
941 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", 976 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
942 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); 977 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
943 978
@@ -945,6 +980,7 @@ public sealed class BSShapeCollection : IDisposable
945 } 980 }
946 else 981 else
947 { 982 {
983 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
948 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", 984 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
949 LogHeader, PhysicsScene.Name); 985 LogHeader, PhysicsScene.Name);
950 } 986 }
@@ -952,7 +988,7 @@ public sealed class BSShapeCollection : IDisposable
952 } 988 }
953 else 989 else
954 { 990 {
955 if (prim.LastAssetBuildFailed) 991 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
956 { 992 {
957 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", 993 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
958 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); 994 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);