diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 293 |
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() { } |