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