aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs293
1 files changed, 218 insertions, 75 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index e6aefd5..dec6b6f 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
230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 251 // Put some informational messages into the log file.
252 m_log.InfoFormat("{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
@@ -268,6 +299,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
268 // Do any replacements in the parameters 299 // Do any replacements in the parameters
269 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 300 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
270 } 301 }
302 else
303 {
304 // Nothing in the configuration INI file so assume unmanaged and other defaults.
305 BulletEngineName = "BulletUnmanaged";
306 m_physicsLoggingEnabled = false;
307 VehicleLoggingEnabled = false;
308 }
271 309
272 // The material characteristics. 310 // The material characteristics.
273 BSMaterials.InitializeFromDefaults(Params); 311 BSMaterials.InitializeFromDefaults(Params);
@@ -311,11 +349,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
311 349
312 switch (selectionName) 350 switch (selectionName)
313 { 351 {
352 case "bullet":
314 case "bulletunmanaged": 353 case "bulletunmanaged":
315 ret = new BSAPIUnman(engineName, this); 354 ret = new BSAPIUnman(engineName, this);
316 break; 355 break;
317 case "bulletxna": 356 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this); 357 ret = new BSAPIXNA(engineName, this);
358 // Disable some features that are not implemented in BulletXNA
359 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
360 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
361 BSParam.ShouldUseBulletHACD = false;
362 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
363 BSParam.ShouldUseSingleConvexHullForPrims = false;
364 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
365 BSParam.ShouldUseGImpactShapeForPrims = false;
366 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
367 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
319 break; 368 break;
320 } 369 }
321 370
@@ -325,7 +374,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
325 } 374 }
326 else 375 else
327 { 376 {
328 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); 377 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
329 } 378 }
330 379
331 return ret; 380 return ret;
@@ -463,7 +512,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
463 512
464 if (!m_initialized) return null; 513 if (!m_initialized) return null;
465 514
466 DetailLog("{0},BSScene.AddPrimShape,call", localID); 515 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
467 516
468 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); 517 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
469 lock (PhysObjects) PhysObjects.Add(localID, prim); 518 lock (PhysObjects) PhysObjects.Add(localID, prim);
@@ -478,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
478 #endregion // Prim and Avatar addition and removal 527 #endregion // Prim and Avatar addition and removal
479 528
480 #region Simulation 529 #region Simulation
481 // 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.
482 public override float Simulate(float timeStep) 537 public override float Simulate(float timeStep)
483 { 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 {
484 // prevent simulation until we've been initialized 550 // prevent simulation until we've been initialized
485 if (!m_initialized) return 5.0f; 551 if (!m_initialized) return;
486 552
487 LastTimeStep = timeStep; 553 LastTimeStep = timeStep;
488 554
489 int updatedEntityCount = 0; 555 int updatedEntityCount = 0;
490 int collidersCount = 0; 556 int collidersCount = 0;
491 557
492 int beforeTime = 0; 558 int beforeTime = Util.EnvironmentTickCount();
493 int simTime = 0; 559 int simTime = 0;
494 560
495 // update the prim states while we know the physics engine is not busy
496 int numTaints = _taintOperations.Count; 561 int numTaints = _taintOperations.Count;
497
498 InTaintTime = true; // Only used for debugging so locking is not necessary. 562 InTaintTime = true; // Only used for debugging so locking is not necessary.
499 563
564 // update the prim states while we know the physics engine is not busy
500 ProcessTaints(); 565 ProcessTaints();
501 566
502 // Some of the physical objects requre individual, pre-step calls 567 // Some of the physical objects requre individual, pre-step calls
@@ -519,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
519 int numSubSteps = 0; 584 int numSubSteps = 0;
520 try 585 try
521 { 586 {
522 if (PhysicsLogging.Enabled)
523 beforeTime = Util.EnvironmentTickCount();
524
525 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);
526 588
527 if (PhysicsLogging.Enabled)
528 {
529 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
530 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
531 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
532 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
533 }
534 } 589 }
535 catch (Exception e) 590 catch (Exception e)
536 { 591 {
@@ -542,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
542 collidersCount = 0; 597 collidersCount = 0;
543 } 598 }
544 599
600 // Make the physics engine dump useful statistics periodically
545 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 601 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
546 PE.DumpPhysicsStatistics(World); 602 PE.DumpPhysicsStatistics(World);
547 603
548 // 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.
549 SimulationNowTime = Util.EnvironmentTickCount(); 605 SimulationNowTime = Util.EnvironmentTickCount();
550 606
551 // 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
552 // Collisions must be processed before updates. 608 // is 'real' (like linksets don't collide with themselves) and the individual objects
553 if (collidersCount > 0) 609 // know if the simulator has subscribed to collisions.
610 lock (CollisionLock)
554 { 611 {
555 for (int ii = 0; ii < collidersCount; ii++) 612 if (collidersCount > 0)
556 { 613 {
557 uint cA = m_collisionArray[ii].aID; 614 for (int ii = 0; ii < collidersCount; ii++)
558 uint cB = m_collisionArray[ii].bID;
559 Vector3 point = m_collisionArray[ii].point;
560 Vector3 normal = m_collisionArray[ii].normal;
561 float penetration = m_collisionArray[ii].penetration;
562 SendCollision(cA, cB, point, normal, penetration);
563 SendCollision(cB, cA, point, -normal, penetration);
564 }
565 }
566
567 // The above SendCollision's batch up the collisions on the objects.
568 // Now push the collisions into the simulator.
569 if (ObjectsWithCollisions.Count > 0)
570 {
571 foreach (BSPhysObject bsp in ObjectsWithCollisions)
572 if (!bsp.SendCollisions())
573 { 615 {
574 // If the object is done colliding, see that it's removed from the colliding list 616 uint cA = m_collisionArray[ii].aID;
575 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);
576 } 623 }
624 }
577 } 625 }
578 626
579 // 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
580 // 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.
581 // The event updates avatar animations and stuff. 629 lock (UpdateLock)
582 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
583 foreach (BSPhysObject bsp in m_avatars)
584 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
585 bsp.SendCollisions();
586
587 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
588 // Not done above because it is inside an iteration of ObjectWithCollisions.
589 // This complex collision processing is required to create an empty collision
590 // event call after all real collisions have happened on an object. This enables
591 // the simulator to generate the 'collision end' event.
592 if (ObjectsWithNoMoreCollisions.Count > 0)
593 {
594 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
595 ObjectsWithCollisions.Remove(po);
596 ObjectsWithNoMoreCollisions.Clear();
597 }
598 // Done with collisions.
599
600 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
601 if (updatedEntityCount > 0)
602 { 630 {
603 for (int ii = 0; ii < updatedEntityCount; ii++) 631 if (updatedEntityCount > 0)
604 { 632 {
605 EntityProperties entprop = m_updateArray[ii]; 633 for (int ii = 0; ii < updatedEntityCount; ii++)
606 BSPhysObject pobj;
607 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
608 { 634 {
609 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 }
610 } 641 }
611 } 642 }
612 } 643 }
613 644
645 // Some actors want to know when the simulation step is complete.
614 TriggerPostStepEvent(timeStep); 646 TriggerPostStepEvent(timeStep);
615 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
616 // 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.
617 // Only enable this in a limited test world with few objects. 657 // Only enable this in a limited test world with few objects.
618 if (m_physicsPhysicalDumpEnabled) 658 if (m_physicsPhysicalDumpEnabled)
@@ -621,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
621 // 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.
622 // 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.
623 // 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).
624 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;
625 } 742 }
626 743
627 // Something has collided 744 // Something has collided
@@ -640,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
640 return; 757 return;
641 } 758 }
642 759
643 // 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.
644 BSPhysObject collidee = null; 761 BSPhysObject collidee = null;
645 PhysObjects.TryGetValue(collidingWith, out collidee); 762 PhysObjects.TryGetValue(collidingWith, out collidee);
646 763
@@ -648,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
648 765
649 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 766 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
650 { 767 {
651 // 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
652 ObjectsWithCollisions.Add(collider); 769 ObjectsWithCollisions.Add(collider);
653 } 770 }
654 771
655 return; 772 return;
656 } 773 }
657 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
658 #endregion // Simulation 801 #endregion // Simulation
659 802
660 public override void GetResults() { } 803 public override void GetResults() { }