diff options
-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() { } |