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.cs332
1 files changed, 248 insertions, 84 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index e6aefd5..c92c9b9 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,63 @@ 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 if (pobj.IsInitialized)
643 pobj.UpdateProperties(entprop);
644 }
610 } 645 }
611 } 646 }
612 } 647 }
613 648
649 // Some actors want to know when the simulation step is complete.
614 TriggerPostStepEvent(timeStep); 650 TriggerPostStepEvent(timeStep);
615 651
652 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
653 if (PhysicsLogging.Enabled)
654 {
655 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
656 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
657 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
658 }
659
616 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 660 // 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. 661 // Only enable this in a limited test world with few objects.
618 if (m_physicsPhysicalDumpEnabled) 662 if (m_physicsPhysicalDumpEnabled)
@@ -621,7 +665,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
621 // The physics engine returns the number of milliseconds it simulated this call. 665 // 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. 666 // 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). 667 // 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; 668 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
669 }
670
671 // Called by a BSPhysObject to note that it has changed properties and this information
672 // should be passed up to the simulator at the proper time.
673 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
674 // this is is under UpdateLock.
675 public void PostUpdate(BSPhysObject updatee)
676 {
677 ObjectsWithUpdates.Add(updatee);
678 }
679
680 // The simulator thinks it is physics time so return all the collisions and position
681 // updates that were collected in actual physics simulation.
682 private float SendUpdatesToSimulator(float timeStep)
683 {
684 if (!m_initialized) return 5.0f;
685
686 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
687 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
688 // Push the collisions into the simulator.
689 lock (CollisionLock)
690 {
691 if (ObjectsWithCollisions.Count > 0)
692 {
693 foreach (BSPhysObject bsp in ObjectsWithCollisions)
694 if (!bsp.SendCollisions())
695 {
696 // If the object is done colliding, see that it's removed from the colliding list
697 ObjectsWithNoMoreCollisions.Add(bsp);
698 }
699 }
700
701 // This is a kludge to get avatar movement updates.
702 // The simulator expects collisions for avatars even if there are have been no collisions.
703 // The event updates avatar animations and stuff.
704 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
705 foreach (BSPhysObject bsp in m_avatars)
706 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
707 bsp.SendCollisions();
708
709 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
710 // Not done above because it is inside an iteration of ObjectWithCollisions.
711 // This complex collision processing is required to create an empty collision
712 // event call after all real collisions have happened on an object. This allows
713 // the simulator to generate the 'collision end' event.
714 if (ObjectsWithNoMoreCollisions.Count > 0)
715 {
716 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
717 ObjectsWithCollisions.Remove(po);
718 ObjectsWithNoMoreCollisions.Clear();
719 }
720 }
721
722 // Call the simulator for each object that has physics property updates.
723 HashSet<BSPhysObject> updatedObjects = null;
724 lock (UpdateLock)
725 {
726 if (ObjectsWithUpdates.Count > 0)
727 {
728 updatedObjects = ObjectsWithUpdates;
729 ObjectsWithUpdates = new HashSet<BSPhysObject>();
730 }
731 }
732 if (updatedObjects != null)
733 {
734 foreach (BSPhysObject obj in updatedObjects)
735 {
736 obj.RequestPhysicsterseUpdate();
737 }
738 updatedObjects.Clear();
739 }
740
741 // Return the framerate simulated to give the above returned results.
742 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
743 float simTime = m_simulatedTime;
744 m_simulatedTime = 0f;
745 return simTime;
625 } 746 }
626 747
627 // Something has collided 748 // Something has collided
@@ -640,21 +761,49 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
640 return; 761 return;
641 } 762 }
642 763
643 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. 764 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
644 BSPhysObject collidee = null; 765 BSPhysObject collidee = null;
645 PhysObjects.TryGetValue(collidingWith, out collidee); 766 PhysObjects.TryGetValue(collidingWith, out collidee);
646 767
647 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); 768 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
648 769
649 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 770 if (collider.IsInitialized)
650 { 771 {
651 // If a collision was posted, remember to send it to the simulator 772 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
652 ObjectsWithCollisions.Add(collider); 773 {
774 // If a collision was 'good', remember to send it to the simulator
775 ObjectsWithCollisions.Add(collider);
776 }
653 } 777 }
654 778
655 return; 779 return;
656 } 780 }
657 781
782 public void BulletSPluginPhysicsThread()
783 {
784 while (m_initialized)
785 {
786 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
787 DoPhysicsStep(BSParam.PhysicsTimeStep);
788 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
789 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
790
791 if (simulationTimeVsRealtimeDifferenceMS > 0)
792 {
793 // The simulation of the time interval took less than realtime.
794 // Do a sleep for the rest of realtime.
795 Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
796 }
797 else
798 {
799 // The simulation took longer than realtime.
800 // Do some scaling of simulation time.
801 // TODO.
802 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
803 }
804 }
805 }
806
658 #endregion // Simulation 807 #endregion // Simulation
659 808
660 public override void GetResults() { } 809 public override void GetResults() { }
@@ -717,6 +866,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
717 866
718 public override bool IsThreaded { get { return false; } } 867 public override bool IsThreaded { get { return false; } }
719 868
869 #region Extensions
870 // =============================================================
871 // Per scene functions. See below.
872
873 // Per avatar functions. See BSCharacter.
874
875 // Per prim functions. See BSPrim.
876 public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
877 public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
878 // =============================================================
879
880 public override object Extension(string pFunct, params object[] pParams)
881 {
882 return base.Extension(pFunct, pParams);
883 }
884 #endregion // Extensions
885
720 #region Taints 886 #region Taints
721 // The simulation execution order is: 887 // The simulation execution order is:
722 // Simulate() 888 // Simulate()
@@ -780,7 +946,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
780 946
781 private void ProcessRegularTaints() 947 private void ProcessRegularTaints()
782 { 948 {
783 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 949 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
784 { 950 {
785 // swizzle a new list into the list location so we can process what's there 951 // swizzle a new list into the list location so we can process what's there
786 List<TaintCallbackEntry> oldList; 952 List<TaintCallbackEntry> oldList;
@@ -823,7 +989,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
823 // Taints that happen after the normal taint processing but before the simulation step. 989 // Taints that happen after the normal taint processing but before the simulation step.
824 private void ProcessPostTaintTaints() 990 private void ProcessPostTaintTaints()
825 { 991 {
826 if (_postTaintOperations.Count > 0) 992 if (m_initialized && _postTaintOperations.Count > 0)
827 { 993 {
828 Dictionary<string, TaintCallbackEntry> oldList; 994 Dictionary<string, TaintCallbackEntry> oldList;
829 lock (_taintLock) 995 lock (_taintLock)
@@ -963,8 +1129,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
963 public void DetailLog(string msg, params Object[] args) 1129 public void DetailLog(string msg, params Object[] args)
964 { 1130 {
965 PhysicsLogging.Write(msg, args); 1131 PhysicsLogging.Write(msg, args);
966 // Add the Flush() if debugging crashes. Gets all the messages written out.
967 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
968 } 1132 }
969 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1133 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
970 public const string DetailLogZero = "0000000000"; 1134 public const string DetailLogZero = "0000000000";