aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs298
1 files changed, 226 insertions, 72 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
index 7ff0a07..163efaa 100644
--- a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -124,9 +124,10 @@ namespace OpenSim.Region.PhysicsModule.BulletS
124 // True if initialized and ready to do simulation steps 124 // True if initialized and ready to do simulation steps
125 private bool m_initialized = false; 125 private bool m_initialized = false;
126 126
127 // Flag which is true when processing taints. 127 // Object locked whenever execution is inside the physics engine
128 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. 128 public Object PhysicsEngineLock = new object();
129 public bool InTaintTime { get; private set; } 129 // Flag that is true when the simulator is active and shouldn't be touched
130 public bool InSimulationTime { get; private set; }
130 131
131 // Pinned memory used to pass step information between managed and unmanaged 132 // Pinned memory used to pass step information between managed and unmanaged
132 internal int m_maxCollisionsPerFrame; 133 internal int m_maxCollisionsPerFrame;
@@ -344,7 +345,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
344 // Put some informational messages into the log file. 345 // Put some informational messages into the log file.
345 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 346 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
346 347
347 InTaintTime = false; 348 InSimulationTime = false;
348 m_initialized = true; 349 m_initialized = true;
349 350
350 // If the physics engine runs on its own thread, start same. 351 // If the physics engine runs on its own thread, start same.
@@ -657,48 +658,57 @@ namespace OpenSim.Region.PhysicsModule.BulletS
657 658
658 int beforeTime = Util.EnvironmentTickCount(); 659 int beforeTime = Util.EnvironmentTickCount();
659 int simTime = 0; 660 int simTime = 0;
661 int numTaints = 0;
662 int numSubSteps = 0;
660 663
661 int numTaints = _taintOperations.Count; 664 lock (PhysicsEngineLock)
662 InTaintTime = true; // Only used for debugging so locking is not necessary. 665 {
666 InSimulationTime = true;
667 // update the prim states while we know the physics engine is not busy
668 numTaints += ProcessTaints();
663 669
664 // update the prim states while we know the physics engine is not busy 670 // Some of the physical objects requre individual, pre-step calls
665 ProcessTaints(); 671 // (vehicles and avatar movement, in particular)
672 TriggerPreStepEvent(timeStep);
666 673
667 // Some of the physical objects requre individual, pre-step calls 674 // the prestep actions might have added taints
668 // (vehicles and avatar movement, in particular) 675 numTaints += ProcessTaints();
669 TriggerPreStepEvent(timeStep);
670 676
671 // the prestep actions might have added taints 677 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
672 numTaints += _taintOperations.Count; 678 // Only enable this in a limited test world with few objects.
673 ProcessTaints(); 679 if (m_physicsPhysicalDumpEnabled)
680 PE.DumpAllInfo(World);
674 681
675 InTaintTime = false; // Only used for debugging so locking is not necessary. 682 // step the physical world one interval
683 m_simulationStep++;
684 try
685 {
686 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
687 }
688 catch (Exception e)
689 {
690 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
691 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
692 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
693 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
694 updatedEntityCount = 0;
695 collidersCount = 0;
696 }
676 697
677 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 698 // Make the physics engine dump useful statistics periodically
678 // Only enable this in a limited test world with few objects. 699 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
679 if (m_physicsPhysicalDumpEnabled) 700 PE.DumpPhysicsStatistics(World);
680 PE.DumpAllInfo(World);
681 701
682 // step the physical world one interval 702 InSimulationTime = false;
683 m_simulationStep++; 703
684 int numSubSteps = 0; 704 // Some actors want to know when the simulation step is complete.
685 try 705 TriggerPostStepEvent(timeStep);
686 { 706
687 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); 707 // In case there were any parameter updates that happened during the simulation step
688 } 708 numTaints += ProcessTaints();
689 catch (Exception e)
690 {
691 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
692 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
693 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
694 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
695 updatedEntityCount = 0;
696 collidersCount = 0;
697 }
698 709
699 // Make the physics engine dump useful statistics periodically 710 InSimulationTime = false;
700 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 711 }
701 PE.DumpPhysicsStatistics(World);
702 712
703 // Get a value for 'now' so all the collision and update routines don't have to get their own. 713 // Get a value for 'now' so all the collision and update routines don't have to get their own.
704 SimulationNowTime = Util.EnvironmentTickCount(); 714 SimulationNowTime = Util.EnvironmentTickCount();
@@ -748,9 +758,6 @@ namespace OpenSim.Region.PhysicsModule.BulletS
748 } 758 }
749 } 759 }
750 760
751 // Some actors want to know when the simulation step is complete.
752 TriggerPostStepEvent(timeStep);
753
754 simTime = Util.EnvironmentTickCountSubtract(beforeTime); 761 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
755 if (PhysicsLogging.Enabled) 762 if (PhysicsLogging.Enabled)
756 { 763 {
@@ -956,6 +963,149 @@ namespace OpenSim.Region.PhysicsModule.BulletS
956 963
957 #endregion // Terrain 964 #endregion // Terrain
958 965
966 #region Raycast
967
968 public override bool SupportsRayCast()
969 {
970 return BSParam.UseBulletRaycast;
971 }
972
973 public override bool SupportsRaycastWorldFiltered()
974 {
975 return BSParam.UseBulletRaycast;
976 }
977
978
979 /// <summary>
980 /// Queue a raycast against the physics scene.
981 /// The provided callback method will be called when the raycast is complete
982 ///
983 /// Many physics engines don't support collision testing at the same time as
984 /// manipulating the physics scene, so we queue the request up and callback
985 /// a custom method when the raycast is complete.
986 /// This allows physics engines that give an immediate result to callback immediately
987 /// and ones that don't, to callback when it gets a result back.
988 /// public delegate void RayCallback(List<ContactResult> list);
989 ///
990 /// ODE for example will not allow you to change the scene while collision testing or
991 /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
992 ///
993 /// This is named RayCastWorld to not conflict with modrex's Raycast method.
994 /// </summary>
995 /// <param name="position">Origin of the ray</param>
996 /// <param name="direction">Direction of the ray</param>
997 /// <param name="length">Length of ray in meters</param>
998 /// <param name="retMethod">Method to call when the raycast is complete</param>
999 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
1000 {
1001 if (retMethod != null)
1002 {
1003 if (BSParam.UseBulletRaycast)
1004 {
1005 Vector3 posFrom = position;
1006 Vector3 posTo = Vector3.Normalize(direction) * length + position;
1007
1008 TaintedObject(DetailLogZero, "BSScene.RaycastWorld1", delegate ()
1009 {
1010 RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, 0xffff, 0xffff);
1011 retMethod(true, hitInfo.Point, hitInfo.ID, hitInfo.Fraction, hitInfo.Normal);
1012 });
1013 }
1014 else
1015 {
1016 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
1017 }
1018 }
1019 }
1020
1021 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
1022 {
1023 if (retMethod != null)
1024 {
1025 if (BSParam.UseBulletRaycast)
1026 {
1027 List<ContactResult> hitInfo = RaycastWorld(position, direction, length, count);
1028 retMethod(hitInfo);
1029 }
1030 else
1031 {
1032 retMethod(new List<ContactResult>());
1033 }
1034 }
1035 }
1036
1037 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int count)
1038 {
1039 return (List<ContactResult>)RaycastWorld(position, direction, length, count, RayFilterFlags.All);
1040 }
1041
1042 public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayFilterFlags filter)
1043 {
1044 List<ContactResult> ret = new List<ContactResult>();
1045 if (BSParam.UseBulletRaycast)
1046 {
1047 uint collisionFilter = 0;
1048 uint collisionMask = 0;
1049 if ((filter & RayFilterFlags.land) != 0)
1050 {
1051 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Terrain].group;
1052 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Terrain].mask;
1053 }
1054 if ((filter & RayFilterFlags.agent) != 0)
1055 {
1056 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Avatar].group;
1057 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Avatar].mask;
1058 }
1059 if ((filter & RayFilterFlags.nonphysical) != 0)
1060 {
1061 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Static].group;
1062 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Static].mask;
1063 }
1064 if ((filter & RayFilterFlags.physical) != 0)
1065 {
1066 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Dynamic].group;
1067 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Dynamic].mask;
1068 }
1069 // if ((filter & RayFilterFlags.phantom) != 0)
1070 // {
1071 // collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].group;
1072 // collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].mask;
1073 // }
1074 if ((filter & RayFilterFlags.volumedtc) != 0)
1075 {
1076 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].group;
1077 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].mask;
1078 }
1079 DetailLog("{0},RaycastWorld,pos={1},dir={2},len={3},count={4},filter={5},filter={6},mask={7}",
1080 DetailLogZero, position, direction, length, count, filter, collisionFilter, collisionMask);
1081 // NOTE: locking ensures the physics engine is not executing.
1082 // The caller might have to wait for the physics engine to finish.
1083 lock (PhysicsEngineLock)
1084 {
1085 Vector3 posFrom = position;
1086 Vector3 posTo = Vector3.Normalize(direction) * length + position;
1087 DetailLog("{0},RaycastWorld,RayTest2,from={1},to={2}",
1088 DetailLogZero, posFrom, posTo);
1089 RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, collisionFilter, collisionMask);
1090 if (hitInfo.hasHit())
1091 {
1092 ContactResult result = new ContactResult();
1093 result.Pos = hitInfo.Point;
1094 result.Normal = hitInfo.Normal;
1095 result.ConsumerID = hitInfo.ID;
1096 result.Depth = hitInfo.Fraction;
1097 ret.Add(result);
1098 DetailLog("{0},RaycastWorld,hit,pos={1},norm={2},depth={3},id={4}",
1099 DetailLogZero, result.Pos, result.Normal, result.Depth, result.ConsumerID);
1100 }
1101 }
1102 }
1103 return ret;
1104 }
1105
1106 #endregion Raycast
1107
1108
959 public override Dictionary<uint, float> GetTopColliders() 1109 public override Dictionary<uint, float> GetTopColliders()
960 { 1110 {
961 Dictionary<uint, float> topColliders; 1111 Dictionary<uint, float> topColliders;
@@ -1068,32 +1218,35 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1068 // Calls to the PhysicsActors can't directly call into the physics engine 1218 // Calls to the PhysicsActors can't directly call into the physics engine
1069 // because it might be busy. We delay changes to a known time. 1219 // because it might be busy. We delay changes to a known time.
1070 // We rely on C#'s closure to save and restore the context for the delegate. 1220 // We rely on C#'s closure to save and restore the context for the delegate.
1071 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback) 1221 // NOTE: 'inTaintTime' is no longer used. This entry exists so all the calls don't have to be changed.
1222 // public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1223 // {
1224 // TaintedObject(BSScene.DetailLogZero, pIdent, pCallback);
1225 // }
1226 // NOTE: 'inTaintTime' is no longer used. This entry exists so all the calls don't have to be changed.
1227 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1072 { 1228 {
1073 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback); 1229 TaintedObject(m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1074 } 1230 }
1075 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback) 1231 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1076 { 1232 {
1077 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); 1233 TaintedObject(m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1078 }
1079 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1080 {
1081 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1082 }
1083 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1084 {
1085 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1086 } 1234 }
1087 // Sometimes a potentially tainted operation can be used in and out of taint time. 1235 // Sometimes a potentially tainted operation can be used in and out of taint time.
1088 // This routine executes the command immediately if in taint-time otherwise it is queued. 1236 // This routine executes the command immediately if in taint-time otherwise it is queued.
1089 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback) 1237 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1090 { 1238 {
1091 if (!m_initialized) return; 1239 if (!m_initialized) return;
1092 1240
1093 if (inTaintTime) 1241 if (Monitor.TryEnter(PhysicsEngineLock))
1242 {
1243 // If we can get exclusive access to the physics engine, just do the operation
1094 pCallback(); 1244 pCallback();
1245 Monitor.Exit(PhysicsEngineLock);
1246 }
1095 else 1247 else
1096 { 1248 {
1249 // The physics engine is busy, queue the operation
1097 lock (_taintLock) 1250 lock (_taintLock)
1098 { 1251 {
1099 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback)); 1252 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
@@ -1120,14 +1273,21 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1120 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 1273 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1121 // a callback into itself to do the actual property change. That callback is called 1274 // a callback into itself to do the actual property change. That callback is called
1122 // here just before the physics engine is called to step the simulation. 1275 // here just before the physics engine is called to step the simulation.
1123 public void ProcessTaints() 1276 // Returns the number of taints processed
1277 // NOTE: Called while PhysicsEngineLock is locked
1278 public int ProcessTaints()
1124 { 1279 {
1125 ProcessRegularTaints(); 1280 int ret = 0;
1126 ProcessPostTaintTaints(); 1281 ret += ProcessRegularTaints();
1282 ret += ProcessPostTaintTaints();
1283 return ret;
1127 } 1284 }
1128 1285
1129 private void ProcessRegularTaints() 1286 // Returns the number of taints processed
1287 // NOTE: Called while PhysicsEngineLock is locked
1288 private int ProcessRegularTaints()
1130 { 1289 {
1290 int ret = 0;
1131 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process 1291 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1132 { 1292 {
1133 // swizzle a new list into the list location so we can process what's there 1293 // swizzle a new list into the list location so we can process what's there
@@ -1144,6 +1304,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1144 { 1304 {
1145 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG 1305 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1146 tcbe.callback(); 1306 tcbe.callback();
1307 ret++;
1147 } 1308 }
1148 catch (Exception e) 1309 catch (Exception e)
1149 { 1310 {
@@ -1152,6 +1313,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1152 } 1313 }
1153 oldList.Clear(); 1314 oldList.Clear();
1154 } 1315 }
1316 return ret;
1155 } 1317 }
1156 1318
1157 // Schedule an update to happen after all the regular taints are processed. 1319 // Schedule an update to happen after all the regular taints are processed.
@@ -1170,8 +1332,11 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1170 } 1332 }
1171 1333
1172 // Taints that happen after the normal taint processing but before the simulation step. 1334 // Taints that happen after the normal taint processing but before the simulation step.
1173 private void ProcessPostTaintTaints() 1335 // Returns the number of taints processed
1336 // NOTE: Called while PhysicsEngineLock is locked
1337 private int ProcessPostTaintTaints()
1174 { 1338 {
1339 int ret = 0;
1175 if (m_initialized && _postTaintOperations.Count > 0) 1340 if (m_initialized && _postTaintOperations.Count > 0)
1176 { 1341 {
1177 Dictionary<string, TaintCallbackEntry> oldList; 1342 Dictionary<string, TaintCallbackEntry> oldList;
@@ -1187,6 +1352,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1187 { 1352 {
1188 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG 1353 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1189 kvp.Value.callback(); 1354 kvp.Value.callback();
1355 ret++;
1190 } 1356 }
1191 catch (Exception e) 1357 catch (Exception e)
1192 { 1358 {
@@ -1195,20 +1361,8 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1195 } 1361 }
1196 oldList.Clear(); 1362 oldList.Clear();
1197 } 1363 }
1364 return ret;
1198 } 1365 }
1199
1200 // Only used for debugging. Does not change state of anything so locking is not necessary.
1201 public bool AssertInTaintTime(string whereFrom)
1202 {
1203 if (!InTaintTime)
1204 {
1205 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1206 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1207 // Util.PrintCallStack(DetailLog);
1208 }
1209 return InTaintTime;
1210 }
1211
1212 #endregion // Taints 1366 #endregion // Taints
1213 1367
1214 #region IPhysicsParameters 1368 #region IPhysicsParameters