diff options
author | Robert Adams | 2013-06-01 14:52:44 -0700 |
---|---|---|
committer | Robert Adams | 2013-06-01 14:52:44 -0700 |
commit | 07058b044be59b6e07efedeca36b2b464e984195 (patch) | |
tree | ee85111ad418be454c2ee9a8d0c0da98b9b99480 /OpenSim/Region/Physics | |
parent | Adding standard OpenSim header to source files (diff) | |
download | opensim-SC_OLD-07058b044be59b6e07efedeca36b2b464e984195.zip opensim-SC_OLD-07058b044be59b6e07efedeca36b2b464e984195.tar.gz opensim-SC_OLD-07058b044be59b6e07efedeca36b2b464e984195.tar.bz2 opensim-SC_OLD-07058b044be59b6e07efedeca36b2b464e984195.tar.xz |
BulletSim: experimental movement of physics execution off of heartbeat
thread. Off by default until more testing.
Setting "[BulletSim]UseSeparatePhysicsThread=true" causes the physics
engine to be called on its own thread and the heartbeat thread only
handles the reporting of property updates and collisions. Physics frame
rate is about right but physics execution time goes to zero as accounted
by the heartbeat loop.
Diffstat (limited to 'OpenSim/Region/Physics')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 8 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 3 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 271 |
3 files changed, 209 insertions, 73 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 2651e3b..afd547a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -54,6 +54,9 @@ public static class BSParam | |||
54 | // =================== | 54 | // =================== |
55 | // From: | 55 | // From: |
56 | 56 | ||
57 | public static bool UseSeparatePhysicsThread { get; private set; } | ||
58 | public static float PhysicsTimeStep { get; private set; } | ||
59 | |||
57 | // Level of Detail values kept as float because that's what the Meshmerizer wants | 60 | // Level of Detail values kept as float because that's what the Meshmerizer wants |
58 | public static float MeshLOD { get; private set; } | 61 | public static float MeshLOD { get; private set; } |
59 | public static float MeshCircularLOD { get; private set; } | 62 | public static float MeshCircularLOD { get; private set; } |
@@ -354,6 +357,11 @@ public static class BSParam | |||
354 | // v = value (appropriate type) | 357 | // v = value (appropriate type) |
355 | private static ParameterDefnBase[] ParameterDefinitions = | 358 | private static ParameterDefnBase[] ParameterDefinitions = |
356 | { | 359 | { |
360 | new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", | ||
361 | false ), | ||
362 | new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", | ||
363 | 0.1f ), | ||
364 | |||
357 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | 365 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", |
358 | true, | 366 | true, |
359 | (s) => { return ShouldMeshSculptedPrim; }, | 367 | (s) => { return ShouldMeshSculptedPrim; }, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e11e365..95bdc7b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -1513,7 +1513,8 @@ public class BSPrim : BSPhysObject | |||
1513 | CurrentEntityProperties = entprop; | 1513 | CurrentEntityProperties = entprop; |
1514 | 1514 | ||
1515 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. | 1515 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. |
1516 | base.RequestPhysicsterseUpdate(); | 1516 | |
1517 | PhysScene.PostUpdate(this); | ||
1517 | } | 1518 | } |
1518 | } | 1519 | } |
1519 | } | 1520 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 39f5b0a..423c389 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
56 | public string BulletEngineName { get; private set; } | 56 | public string BulletEngineName { get; private set; } |
57 | public BSAPITemplate PE; | 57 | public BSAPITemplate PE; |
58 | 58 | ||
59 | // If the physics engine is running on a separate thread | ||
60 | public Thread m_physicsThread; | ||
61 | |||
59 | public Dictionary<uint, BSPhysObject> PhysObjects; | 62 | public Dictionary<uint, BSPhysObject> PhysObjects; |
60 | public BSShapeCollection Shapes; | 63 | public BSShapeCollection Shapes; |
61 | 64 | ||
62 | // Keeping track of the objects with collisions so we can report begin and end of a collision | 65 | // Keeping track of the objects with collisions so we can report begin and end of a collision |
63 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | 66 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); |
64 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | 67 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); |
68 | |||
69 | // All the collision processing is protected with this lock object | ||
70 | public Object CollisionLock = new Object(); | ||
71 | |||
72 | // Properties are updated here | ||
73 | public Object UpdateLock = new Object(); | ||
74 | public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
75 | |||
65 | // Keep track of all the avatars so we can send them a collision event | 76 | // Keep track of all the avatars so we can send them a collision event |
66 | // every tick so OpenSim will update its animation. | 77 | // every tick so OpenSim will update its animation. |
67 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 78 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |
@@ -77,12 +88,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
77 | public BSConstraintCollection Constraints { get; private set; } | 88 | public BSConstraintCollection Constraints { get; private set; } |
78 | 89 | ||
79 | // Simulation parameters | 90 | // Simulation parameters |
91 | internal float m_physicsStepTime; // if running independently, the interval simulated by default | ||
92 | |||
80 | internal int m_maxSubSteps; | 93 | internal int m_maxSubSteps; |
81 | internal float m_fixedTimeStep; | 94 | internal float m_fixedTimeStep; |
82 | internal long m_simulationStep = 0; | 95 | |
83 | internal float NominalFrameRate { get; set; } | 96 | internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc. |
97 | |||
98 | internal long m_simulationStep = 0; // The current simulation step. | ||
84 | public long SimulationStep { get { return m_simulationStep; } } | 99 | public long SimulationStep { get { return m_simulationStep; } } |
85 | internal float LastTimeStep { get; private set; } | 100 | |
101 | internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() | ||
102 | |||
103 | internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to | ||
86 | 104 | ||
87 | // Physical objects can register for prestep or poststep events | 105 | // Physical objects can register for prestep or poststep events |
88 | public delegate void PreStepAction(float timeStep); | 106 | public delegate void PreStepAction(float timeStep); |
@@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | public event PreStepAction BeforeStep; | 108 | public event PreStepAction BeforeStep; |
91 | public event PostStepAction AfterStep; | 109 | public event PostStepAction AfterStep; |
92 | 110 | ||
93 | // A value of the time now so all the collision and update routines do not have to get their own | 111 | // A value of the time 'now' so all the collision and update routines do not have to get their own |
94 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 112 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
95 | public int SimulationNowTime { get; private set; } | 113 | public int SimulationNowTime { get; private set; } |
96 | 114 | ||
@@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
188 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | 206 | PhysObjects = new Dictionary<uint, BSPhysObject>(); |
189 | Shapes = new BSShapeCollection(this); | 207 | Shapes = new BSShapeCollection(this); |
190 | 208 | ||
209 | m_simulatedTime = 0f; | ||
210 | LastTimeStep = 0.1f; | ||
211 | |||
191 | // Allocate pinned memory to pass parameters. | 212 | // Allocate pinned memory to pass parameters. |
192 | UnmanagedParams = new ConfigurationParameters[1]; | 213 | UnmanagedParams = new ConfigurationParameters[1]; |
193 | 214 | ||
@@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
227 | TerrainManager = new BSTerrainManager(this); | 248 | TerrainManager = new BSTerrainManager(this); |
228 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 249 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
229 | 250 | ||
251 | // Put some informational messages into the log file. | ||
230 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | 252 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); |
231 | 253 | ||
232 | InTaintTime = false; | 254 | InTaintTime = false; |
233 | m_initialized = true; | 255 | m_initialized = true; |
256 | |||
257 | // If the physics engine runs on its own thread, start same. | ||
258 | if (BSParam.UseSeparatePhysicsThread) | ||
259 | { | ||
260 | // The physics simulation should happen independently of the heartbeat loop | ||
261 | m_physicsThread = new Thread(BulletSPluginPhysicsThread); | ||
262 | m_physicsThread.Name = BulletEngineName; | ||
263 | m_physicsThread.Start(); | ||
264 | } | ||
234 | } | 265 | } |
235 | 266 | ||
236 | // All default parameter values are set here. There should be no values set in the | 267 | // All default parameter values are set here. There should be no values set in the |
@@ -270,6 +301,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
270 | } | 301 | } |
271 | else | 302 | else |
272 | { | 303 | { |
304 | // Nothing in the configuration INI file so assume unmanaged and other defaults. | ||
273 | BulletEngineName = "BulletUnmanaged"; | 305 | BulletEngineName = "BulletUnmanaged"; |
274 | m_physicsLoggingEnabled = false; | 306 | m_physicsLoggingEnabled = false; |
275 | VehicleLoggingEnabled = false; | 307 | VehicleLoggingEnabled = false; |
@@ -317,6 +349,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
317 | 349 | ||
318 | switch (selectionName) | 350 | switch (selectionName) |
319 | { | 351 | { |
352 | case "bullet": | ||
320 | case "bulletunmanaged": | 353 | case "bulletunmanaged": |
321 | ret = new BSAPIUnman(engineName, this); | 354 | ret = new BSAPIUnman(engineName, this); |
322 | break; | 355 | break; |
@@ -494,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
494 | #endregion // Prim and Avatar addition and removal | 527 | #endregion // Prim and Avatar addition and removal |
495 | 528 | ||
496 | #region Simulation | 529 | #region Simulation |
497 | // Simulate one timestep | 530 | |
531 | // Call from the simulator to send physics information to the simulator objects. | ||
532 | // This pushes all the collision and property update events into the objects in | ||
533 | // the simulator and, since it is on the heartbeat thread, there is an implicit | ||
534 | // locking of those data structures from other heartbeat events. | ||
535 | // If the physics engine is running on a separate thread, the update information | ||
536 | // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. | ||
498 | public override float Simulate(float timeStep) | 537 | public override float Simulate(float timeStep) |
499 | { | 538 | { |
539 | if (!BSParam.UseSeparatePhysicsThread) | ||
540 | { | ||
541 | DoPhysicsStep(timeStep); | ||
542 | } | ||
543 | return SendUpdatesToSimulator(timeStep); | ||
544 | } | ||
545 | |||
546 | // Call the physics engine to do one 'timeStep' and collect collisions and updates | ||
547 | // into ObjectsWithCollisions and ObjectsWithUpdates data structures. | ||
548 | private void DoPhysicsStep(float timeStep) | ||
549 | { | ||
500 | // prevent simulation until we've been initialized | 550 | // prevent simulation until we've been initialized |
501 | if (!m_initialized) return 5.0f; | 551 | if (!m_initialized) return; |
502 | 552 | ||
503 | LastTimeStep = timeStep; | 553 | LastTimeStep = timeStep; |
504 | 554 | ||
505 | int updatedEntityCount = 0; | 555 | int updatedEntityCount = 0; |
506 | int collidersCount = 0; | 556 | int collidersCount = 0; |
507 | 557 | ||
508 | int beforeTime = 0; | 558 | int beforeTime = Util.EnvironmentTickCount(); |
509 | int simTime = 0; | 559 | int simTime = 0; |
510 | 560 | ||
511 | // update the prim states while we know the physics engine is not busy | ||
512 | int numTaints = _taintOperations.Count; | 561 | int numTaints = _taintOperations.Count; |
513 | |||
514 | InTaintTime = true; // Only used for debugging so locking is not necessary. | 562 | InTaintTime = true; // Only used for debugging so locking is not necessary. |
515 | 563 | ||
564 | // update the prim states while we know the physics engine is not busy | ||
516 | ProcessTaints(); | 565 | ProcessTaints(); |
517 | 566 | ||
518 | // Some of the physical objects requre individual, pre-step calls | 567 | // Some of the physical objects requre individual, pre-step calls |
@@ -535,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
535 | int numSubSteps = 0; | 584 | int numSubSteps = 0; |
536 | try | 585 | try |
537 | { | 586 | { |
538 | if (PhysicsLogging.Enabled) | ||
539 | beforeTime = Util.EnvironmentTickCount(); | ||
540 | |||
541 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); | 587 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
542 | 588 | ||
543 | if (PhysicsLogging.Enabled) | ||
544 | { | ||
545 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
546 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
547 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
548 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
549 | } | ||
550 | } | 589 | } |
551 | catch (Exception e) | 590 | catch (Exception e) |
552 | { | 591 | { |
@@ -558,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
558 | collidersCount = 0; | 597 | collidersCount = 0; |
559 | } | 598 | } |
560 | 599 | ||
600 | // Make the physics engine dump useful statistics periodically | ||
561 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) | 601 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
562 | PE.DumpPhysicsStatistics(World); | 602 | PE.DumpPhysicsStatistics(World); |
563 | 603 | ||
564 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 604 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
565 | SimulationNowTime = Util.EnvironmentTickCount(); | 605 | SimulationNowTime = Util.EnvironmentTickCount(); |
566 | 606 | ||
567 | // If there were collisions, process them by sending the event to the prim. | 607 | // Send collision information to the colliding objects. The objects decide if the collision |
568 | // Collisions must be processed before updates. | 608 | // is 'real' (like linksets don't collide with themselves) and the individual objects |
569 | if (collidersCount > 0) | 609 | // know if the simulator has subscribed to collisions. |
610 | lock (CollisionLock) | ||
570 | { | 611 | { |
571 | for (int ii = 0; ii < collidersCount; ii++) | 612 | if (collidersCount > 0) |
572 | { | 613 | { |
573 | uint cA = m_collisionArray[ii].aID; | 614 | for (int ii = 0; ii < collidersCount; ii++) |
574 | uint cB = m_collisionArray[ii].bID; | ||
575 | Vector3 point = m_collisionArray[ii].point; | ||
576 | Vector3 normal = m_collisionArray[ii].normal; | ||
577 | float penetration = m_collisionArray[ii].penetration; | ||
578 | SendCollision(cA, cB, point, normal, penetration); | ||
579 | SendCollision(cB, cA, point, -normal, penetration); | ||
580 | } | ||
581 | } | ||
582 | |||
583 | // The above SendCollision's batch up the collisions on the objects. | ||
584 | // Now push the collisions into the simulator. | ||
585 | if (ObjectsWithCollisions.Count > 0) | ||
586 | { | ||
587 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
588 | if (!bsp.SendCollisions()) | ||
589 | { | 615 | { |
590 | // If the object is done colliding, see that it's removed from the colliding list | 616 | uint cA = m_collisionArray[ii].aID; |
591 | ObjectsWithNoMoreCollisions.Add(bsp); | 617 | uint cB = m_collisionArray[ii].bID; |
618 | Vector3 point = m_collisionArray[ii].point; | ||
619 | Vector3 normal = m_collisionArray[ii].normal; | ||
620 | float penetration = m_collisionArray[ii].penetration; | ||
621 | SendCollision(cA, cB, point, normal, penetration); | ||
622 | SendCollision(cB, cA, point, -normal, penetration); | ||
592 | } | 623 | } |
624 | } | ||
593 | } | 625 | } |
594 | 626 | ||
595 | // This is a kludge to get avatar movement updates. | 627 | // If any of the objects had updated properties, tell the managed objects about the update |
596 | // The simulator expects collisions for avatars even if there are have been no collisions. | 628 | // and remember that there was a change so it will be passed to the simulator. |
597 | // The event updates avatar animations and stuff. | 629 | lock (UpdateLock) |
598 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
599 | foreach (BSPhysObject bsp in m_avatars) | ||
600 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
601 | bsp.SendCollisions(); | ||
602 | |||
603 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
604 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
605 | // This complex collision processing is required to create an empty collision | ||
606 | // event call after all real collisions have happened on an object. This enables | ||
607 | // the simulator to generate the 'collision end' event. | ||
608 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
609 | { | ||
610 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
611 | ObjectsWithCollisions.Remove(po); | ||
612 | ObjectsWithNoMoreCollisions.Clear(); | ||
613 | } | ||
614 | // Done with collisions. | ||
615 | |||
616 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | ||
617 | if (updatedEntityCount > 0) | ||
618 | { | 630 | { |
619 | for (int ii = 0; ii < updatedEntityCount; ii++) | 631 | if (updatedEntityCount > 0) |
620 | { | 632 | { |
621 | EntityProperties entprop = m_updateArray[ii]; | 633 | for (int ii = 0; ii < updatedEntityCount; ii++) |
622 | BSPhysObject pobj; | ||
623 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
624 | { | 634 | { |
625 | pobj.UpdateProperties(entprop); | 635 | EntityProperties entprop = m_updateArray[ii]; |
636 | BSPhysObject pobj; | ||
637 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
638 | { | ||
639 | pobj.UpdateProperties(entprop); | ||
640 | } | ||
626 | } | 641 | } |
627 | } | 642 | } |
628 | } | 643 | } |
629 | 644 | ||
645 | // Some actors want to know when the simulation step is complete. | ||
630 | TriggerPostStepEvent(timeStep); | 646 | TriggerPostStepEvent(timeStep); |
631 | 647 | ||
648 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
649 | if (PhysicsLogging.Enabled) | ||
650 | { | ||
651 | DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
652 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
653 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
654 | } | ||
655 | |||
632 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 656 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
633 | // Only enable this in a limited test world with few objects. | 657 | // Only enable this in a limited test world with few objects. |
634 | if (m_physicsPhysicalDumpEnabled) | 658 | if (m_physicsPhysicalDumpEnabled) |
@@ -637,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
637 | // The physics engine returns the number of milliseconds it simulated this call. | 661 | // The physics engine returns the number of milliseconds it simulated this call. |
638 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 662 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
639 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). | 663 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). |
640 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; | 664 | m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
665 | } | ||
666 | |||
667 | // Called by a BSPhysObject to note that it has changed properties and this information | ||
668 | // should be passed up to the simulator at the proper time. | ||
669 | // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so | ||
670 | // this is is under UpdateLock. | ||
671 | public void PostUpdate(BSPhysObject updatee) | ||
672 | { | ||
673 | ObjectsWithUpdates.Add(updatee); | ||
674 | } | ||
675 | |||
676 | // The simulator thinks it is physics time so return all the collisions and position | ||
677 | // updates that were collected in actual physics simulation. | ||
678 | private float SendUpdatesToSimulator(float timeStep) | ||
679 | { | ||
680 | if (!m_initialized) return 5.0f; | ||
681 | |||
682 | DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", | ||
683 | BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); | ||
684 | // Push the collisions into the simulator. | ||
685 | lock (CollisionLock) | ||
686 | { | ||
687 | if (ObjectsWithCollisions.Count > 0) | ||
688 | { | ||
689 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
690 | if (!bsp.SendCollisions()) | ||
691 | { | ||
692 | // If the object is done colliding, see that it's removed from the colliding list | ||
693 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | // This is a kludge to get avatar movement updates. | ||
698 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
699 | // The event updates avatar animations and stuff. | ||
700 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
701 | foreach (BSPhysObject bsp in m_avatars) | ||
702 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
703 | bsp.SendCollisions(); | ||
704 | |||
705 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
706 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
707 | // This complex collision processing is required to create an empty collision | ||
708 | // event call after all real collisions have happened on an object. This allows | ||
709 | // the simulator to generate the 'collision end' event. | ||
710 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
711 | { | ||
712 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
713 | ObjectsWithCollisions.Remove(po); | ||
714 | ObjectsWithNoMoreCollisions.Clear(); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | // Call the simulator for each object that has physics property updates. | ||
719 | HashSet<BSPhysObject> updatedObjects = null; | ||
720 | lock (UpdateLock) | ||
721 | { | ||
722 | if (ObjectsWithUpdates.Count > 0) | ||
723 | { | ||
724 | updatedObjects = ObjectsWithUpdates; | ||
725 | ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
726 | } | ||
727 | } | ||
728 | if (updatedObjects != null) | ||
729 | { | ||
730 | foreach (BSPhysObject obj in updatedObjects) | ||
731 | { | ||
732 | obj.RequestPhysicsterseUpdate(); | ||
733 | } | ||
734 | updatedObjects.Clear(); | ||
735 | } | ||
736 | |||
737 | // Return the framerate simulated to give the above returned results. | ||
738 | // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). | ||
739 | float simTime = m_simulatedTime; | ||
740 | m_simulatedTime = 0f; | ||
741 | return simTime; | ||
641 | } | 742 | } |
642 | 743 | ||
643 | // Something has collided | 744 | // Something has collided |
@@ -656,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
656 | return; | 757 | return; |
657 | } | 758 | } |
658 | 759 | ||
659 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 760 | // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. |
660 | BSPhysObject collidee = null; | 761 | BSPhysObject collidee = null; |
661 | PhysObjects.TryGetValue(collidingWith, out collidee); | 762 | PhysObjects.TryGetValue(collidingWith, out collidee); |
662 | 763 | ||
@@ -664,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
664 | 765 | ||
665 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 766 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
666 | { | 767 | { |
667 | // If a collision was posted, remember to send it to the simulator | 768 | // If a collision was 'good', remember to send it to the simulator |
668 | ObjectsWithCollisions.Add(collider); | 769 | ObjectsWithCollisions.Add(collider); |
669 | } | 770 | } |
670 | 771 | ||
671 | return; | 772 | return; |
672 | } | 773 | } |
673 | 774 | ||
775 | public void BulletSPluginPhysicsThread() | ||
776 | { | ||
777 | while (m_initialized) | ||
778 | { | ||
779 | int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); | ||
780 | DoPhysicsStep(BSParam.PhysicsTimeStep); | ||
781 | int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); | ||
782 | int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; | ||
783 | |||
784 | if (simulationTimeVsRealtimeDifferenceMS > 0) | ||
785 | { | ||
786 | // The simulation of the time interval took less than realtime. | ||
787 | // Do a sleep for the rest of realtime. | ||
788 | DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
789 | Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | // The simulation took longer than realtime. | ||
794 | // Do some scaling of simulation time. | ||
795 | // TODO. | ||
796 | DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
674 | #endregion // Simulation | 801 | #endregion // Simulation |
675 | 802 | ||
676 | public override void GetResults() { } | 803 | public override void GetResults() { } |