aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs303
1 files changed, 223 insertions, 80 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index e6aefd5..41aca3b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -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,22 @@ 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 // A number to use for SimulationStep that is probably not any step value
101 // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
102 public static long NotASimulationStep = -1234;
103
104 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
105
106 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
86 107
87 // Physical objects can register for prestep or poststep events 108 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep); 109 public delegate void PreStepAction(float timeStep);
@@ -90,7 +111,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
90 public event PreStepAction BeforeStep; 111 public event PreStepAction BeforeStep;
91 public event PostStepAction AfterStep; 112 public event PostStepAction AfterStep;
92 113
93 // A value of the time now so all the collision and update routines do not have to get their own 114 // 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 115 // Set to 'now' just before all the prims and actors are called for collisions and updates
95 public int SimulationNowTime { get; private set; } 116 public int SimulationNowTime { get; private set; }
96 117
@@ -188,6 +209,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
188 PhysObjects = new Dictionary<uint, BSPhysObject>(); 209 PhysObjects = new Dictionary<uint, BSPhysObject>();
189 Shapes = new BSShapeCollection(this); 210 Shapes = new BSShapeCollection(this);
190 211
212 m_simulatedTime = 0f;
213 LastTimeStep = 0.1f;
214
191 // Allocate pinned memory to pass parameters. 215 // Allocate pinned memory to pass parameters.
192 UnmanagedParams = new ConfigurationParameters[1]; 216 UnmanagedParams = new ConfigurationParameters[1];
193 217
@@ -202,8 +226,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
202 // can be left in and every call doesn't have to check for null. 226 // can be left in and every call doesn't have to check for null.
203 if (m_physicsLoggingEnabled) 227 if (m_physicsLoggingEnabled)
204 { 228 {
205 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 229 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
206 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. 230 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
207 } 231 }
208 else 232 else
209 { 233 {
@@ -227,10 +251,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
227 TerrainManager = new BSTerrainManager(this); 251 TerrainManager = new BSTerrainManager(this);
228 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 252 TerrainManager.CreateInitialGroundPlaneAndTerrain();
229 253
230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 254 // Put some informational messages into the log file.
255 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
231 256
232 InTaintTime = false; 257 InTaintTime = false;
233 m_initialized = true; 258 m_initialized = true;
259
260 // If the physics engine runs on its own thread, start same.
261 if (BSParam.UseSeparatePhysicsThread)
262 {
263 // The physics simulation should happen independently of the heartbeat loop
264 m_physicsThread = new Thread(BulletSPluginPhysicsThread);
265 m_physicsThread.Name = BulletEngineName;
266 m_physicsThread.Start();
267 }
234 } 268 }
235 269
236 // All default parameter values are set here. There should be no values set in the 270 // All default parameter values are set here. There should be no values set in the
@@ -268,6 +302,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
268 // Do any replacements in the parameters 302 // Do any replacements in the parameters
269 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 303 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
270 } 304 }
305 else
306 {
307 // Nothing in the configuration INI file so assume unmanaged and other defaults.
308 BulletEngineName = "BulletUnmanaged";
309 m_physicsLoggingEnabled = false;
310 VehicleLoggingEnabled = false;
311 }
271 312
272 // The material characteristics. 313 // The material characteristics.
273 BSMaterials.InitializeFromDefaults(Params); 314 BSMaterials.InitializeFromDefaults(Params);
@@ -311,11 +352,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
311 352
312 switch (selectionName) 353 switch (selectionName)
313 { 354 {
355 case "bullet":
314 case "bulletunmanaged": 356 case "bulletunmanaged":
315 ret = new BSAPIUnman(engineName, this); 357 ret = new BSAPIUnman(engineName, this);
316 break; 358 break;
317 case "bulletxna": 359 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this); 360 ret = new BSAPIXNA(engineName, this);
361 // Disable some features that are not implemented in BulletXNA
362 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
363 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
364 BSParam.ShouldUseBulletHACD = false;
365 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
366 BSParam.ShouldUseSingleConvexHullForPrims = false;
367 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
368 BSParam.ShouldUseGImpactShapeForPrims = false;
369 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
370 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
319 break; 371 break;
320 } 372 }
321 373
@@ -325,7 +377,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
325 } 377 }
326 else 378 else
327 { 379 {
328 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); 380 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
329 } 381 }
330 382
331 return ret; 383 return ret;
@@ -463,7 +515,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
463 515
464 if (!m_initialized) return null; 516 if (!m_initialized) return null;
465 517
466 DetailLog("{0},BSScene.AddPrimShape,call", localID); 518 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
467 519
468 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); 520 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
469 lock (PhysObjects) PhysObjects.Add(localID, prim); 521 lock (PhysObjects) PhysObjects.Add(localID, prim);
@@ -478,25 +530,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
478 #endregion // Prim and Avatar addition and removal 530 #endregion // Prim and Avatar addition and removal
479 531
480 #region Simulation 532 #region Simulation
481 // Simulate one timestep 533
534 // Call from the simulator to send physics information to the simulator objects.
535 // This pushes all the collision and property update events into the objects in
536 // the simulator and, since it is on the heartbeat thread, there is an implicit
537 // locking of those data structures from other heartbeat events.
538 // If the physics engine is running on a separate thread, the update information
539 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
482 public override float Simulate(float timeStep) 540 public override float Simulate(float timeStep)
483 { 541 {
542 if (!BSParam.UseSeparatePhysicsThread)
543 {
544 DoPhysicsStep(timeStep);
545 }
546 return SendUpdatesToSimulator(timeStep);
547 }
548
549 // Call the physics engine to do one 'timeStep' and collect collisions and updates
550 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
551 private void DoPhysicsStep(float timeStep)
552 {
484 // prevent simulation until we've been initialized 553 // prevent simulation until we've been initialized
485 if (!m_initialized) return 5.0f; 554 if (!m_initialized) return;
486 555
487 LastTimeStep = timeStep; 556 LastTimeStep = timeStep;
488 557
489 int updatedEntityCount = 0; 558 int updatedEntityCount = 0;
490 int collidersCount = 0; 559 int collidersCount = 0;
491 560
492 int beforeTime = 0; 561 int beforeTime = Util.EnvironmentTickCount();
493 int simTime = 0; 562 int simTime = 0;
494 563
495 // update the prim states while we know the physics engine is not busy
496 int numTaints = _taintOperations.Count; 564 int numTaints = _taintOperations.Count;
497
498 InTaintTime = true; // Only used for debugging so locking is not necessary. 565 InTaintTime = true; // Only used for debugging so locking is not necessary.
499 566
567 // update the prim states while we know the physics engine is not busy
500 ProcessTaints(); 568 ProcessTaints();
501 569
502 // Some of the physical objects requre individual, pre-step calls 570 // Some of the physical objects requre individual, pre-step calls
@@ -519,18 +587,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
519 int numSubSteps = 0; 587 int numSubSteps = 0;
520 try 588 try
521 { 589 {
522 if (PhysicsLogging.Enabled)
523 beforeTime = Util.EnvironmentTickCount();
524
525 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); 590 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
526 591
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 } 592 }
535 catch (Exception e) 593 catch (Exception e)
536 { 594 {
@@ -542,77 +600,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
542 collidersCount = 0; 600 collidersCount = 0;
543 } 601 }
544 602
603 // Make the physics engine dump useful statistics periodically
545 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 604 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
546 PE.DumpPhysicsStatistics(World); 605 PE.DumpPhysicsStatistics(World);
547 606
548 // Get a value for 'now' so all the collision and update routines don't have to get their own. 607 // Get a value for 'now' so all the collision and update routines don't have to get their own.
549 SimulationNowTime = Util.EnvironmentTickCount(); 608 SimulationNowTime = Util.EnvironmentTickCount();
550 609
551 // If there were collisions, process them by sending the event to the prim. 610 // Send collision information to the colliding objects. The objects decide if the collision
552 // Collisions must be processed before updates. 611 // is 'real' (like linksets don't collide with themselves) and the individual objects
553 if (collidersCount > 0) 612 // know if the simulator has subscribed to collisions.
613 lock (CollisionLock)
554 { 614 {
555 for (int ii = 0; ii < collidersCount; ii++) 615 if (collidersCount > 0)
556 { 616 {
557 uint cA = m_collisionArray[ii].aID; 617 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 { 618 {
574 // If the object is done colliding, see that it's removed from the colliding list 619 uint cA = m_collisionArray[ii].aID;
575 ObjectsWithNoMoreCollisions.Add(bsp); 620 uint cB = m_collisionArray[ii].bID;
621 Vector3 point = m_collisionArray[ii].point;
622 Vector3 normal = m_collisionArray[ii].normal;
623 float penetration = m_collisionArray[ii].penetration;
624 SendCollision(cA, cB, point, normal, penetration);
625 SendCollision(cB, cA, point, -normal, penetration);
576 } 626 }
627 }
577 } 628 }
578 629
579 // This is a kludge to get avatar movement updates. 630 // 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. 631 // and remember that there was a change so it will be passed to the simulator.
581 // The event updates avatar animations and stuff. 632 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 { 633 {
603 for (int ii = 0; ii < updatedEntityCount; ii++) 634 if (updatedEntityCount > 0)
604 { 635 {
605 EntityProperties entprop = m_updateArray[ii]; 636 for (int ii = 0; ii < updatedEntityCount; ii++)
606 BSPhysObject pobj;
607 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
608 { 637 {
609 pobj.UpdateProperties(entprop); 638 EntityProperties entprop = m_updateArray[ii];
639 BSPhysObject pobj;
640 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
641 {
642 pobj.UpdateProperties(entprop);
643 }
610 } 644 }
611 } 645 }
612 } 646 }
613 647
648 // Some actors want to know when the simulation step is complete.
614 TriggerPostStepEvent(timeStep); 649 TriggerPostStepEvent(timeStep);
615 650
651 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
652 if (PhysicsLogging.Enabled)
653 {
654 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
655 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
656 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
657 }
658
616 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 659 // 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. 660 // Only enable this in a limited test world with few objects.
618 if (m_physicsPhysicalDumpEnabled) 661 if (m_physicsPhysicalDumpEnabled)
@@ -621,7 +664,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
621 // The physics engine returns the number of milliseconds it simulated this call. 664 // 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. 665 // 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). 666 // 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; 667 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
668 }
669
670 // Called by a BSPhysObject to note that it has changed properties and this information
671 // should be passed up to the simulator at the proper time.
672 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
673 // this is is under UpdateLock.
674 public void PostUpdate(BSPhysObject updatee)
675 {
676 ObjectsWithUpdates.Add(updatee);
677 }
678
679 // The simulator thinks it is physics time so return all the collisions and position
680 // updates that were collected in actual physics simulation.
681 private float SendUpdatesToSimulator(float timeStep)
682 {
683 if (!m_initialized) return 5.0f;
684
685 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
686 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
687 // Push the collisions into the simulator.
688 lock (CollisionLock)
689 {
690 if (ObjectsWithCollisions.Count > 0)
691 {
692 foreach (BSPhysObject bsp in ObjectsWithCollisions)
693 if (!bsp.SendCollisions())
694 {
695 // If the object is done colliding, see that it's removed from the colliding list
696 ObjectsWithNoMoreCollisions.Add(bsp);
697 }
698 }
699
700 // This is a kludge to get avatar movement updates.
701 // The simulator expects collisions for avatars even if there are have been no collisions.
702 // The event updates avatar animations and stuff.
703 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
704 foreach (BSPhysObject bsp in m_avatars)
705 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
706 bsp.SendCollisions();
707
708 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
709 // Not done above because it is inside an iteration of ObjectWithCollisions.
710 // This complex collision processing is required to create an empty collision
711 // event call after all real collisions have happened on an object. This allows
712 // the simulator to generate the 'collision end' event.
713 if (ObjectsWithNoMoreCollisions.Count > 0)
714 {
715 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
716 ObjectsWithCollisions.Remove(po);
717 ObjectsWithNoMoreCollisions.Clear();
718 }
719 }
720
721 // Call the simulator for each object that has physics property updates.
722 HashSet<BSPhysObject> updatedObjects = null;
723 lock (UpdateLock)
724 {
725 if (ObjectsWithUpdates.Count > 0)
726 {
727 updatedObjects = ObjectsWithUpdates;
728 ObjectsWithUpdates = new HashSet<BSPhysObject>();
729 }
730 }
731 if (updatedObjects != null)
732 {
733 foreach (BSPhysObject obj in updatedObjects)
734 {
735 obj.RequestPhysicsterseUpdate();
736 }
737 updatedObjects.Clear();
738 }
739
740 // Return the framerate simulated to give the above returned results.
741 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
742 float simTime = m_simulatedTime;
743 m_simulatedTime = 0f;
744 return simTime;
625 } 745 }
626 746
627 // Something has collided 747 // Something has collided
@@ -640,7 +760,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
640 return; 760 return;
641 } 761 }
642 762
643 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. 763 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
644 BSPhysObject collidee = null; 764 BSPhysObject collidee = null;
645 PhysObjects.TryGetValue(collidingWith, out collidee); 765 PhysObjects.TryGetValue(collidingWith, out collidee);
646 766
@@ -648,13 +768,38 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
648 768
649 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 769 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
650 { 770 {
651 // If a collision was posted, remember to send it to the simulator 771 // If a collision was 'good', remember to send it to the simulator
652 ObjectsWithCollisions.Add(collider); 772 ObjectsWithCollisions.Add(collider);
653 } 773 }
654 774
655 return; 775 return;
656 } 776 }
657 777
778 public void BulletSPluginPhysicsThread()
779 {
780 while (m_initialized)
781 {
782 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
783 DoPhysicsStep(BSParam.PhysicsTimeStep);
784 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
785 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
786
787 if (simulationTimeVsRealtimeDifferenceMS > 0)
788 {
789 // The simulation of the time interval took less than realtime.
790 // Do a sleep for the rest of realtime.
791 Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
792 }
793 else
794 {
795 // The simulation took longer than realtime.
796 // Do some scaling of simulation time.
797 // TODO.
798 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
799 }
800 }
801 }
802
658 #endregion // Simulation 803 #endregion // Simulation
659 804
660 public override void GetResults() { } 805 public override void GetResults() { }
@@ -963,8 +1108,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
963 public void DetailLog(string msg, params Object[] args) 1108 public void DetailLog(string msg, params Object[] args)
964 { 1109 {
965 PhysicsLogging.Write(msg, args); 1110 PhysicsLogging.Write(msg, args);
966 // Add the Flush() if debugging crashes. Gets all the messages written out.
967 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
968 } 1111 }
969 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1112 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
970 public const string DetailLogZero = "0000000000"; 1113 public const string DetailLogZero = "0000000000";