diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 232 |
1 files changed, 147 insertions, 85 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index aaed7de..6621d39 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,7 +39,6 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Move all logic out of the C++ code and into the C# code for easier future modifications. | ||
43 | // Test sculpties (verified that they don't work) | 42 | // Test sculpties (verified that they don't work) |
44 | // Compute physics FPS reasonably | 43 | // Compute physics FPS reasonably |
45 | // Based on material, set density and friction | 44 | // Based on material, set density and friction |
@@ -90,10 +89,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | // let my minuions use my logger | 89 | // let my minuions use my logger |
91 | public ILog Logger { get { return m_log; } } | 90 | public ILog Logger { get { return m_log; } } |
92 | 91 | ||
93 | // If non-zero, the number of simulation steps between calls to the physics | ||
94 | // engine to output detailed physics stats. Debug logging level must be on also. | ||
95 | private int m_detailedStatsStep = 0; | ||
96 | |||
97 | public IMesher mesher; | 92 | public IMesher mesher; |
98 | // Level of Detail values kept as float because that's what the Meshmerizer wants | 93 | // Level of Detail values kept as float because that's what the Meshmerizer wants |
99 | public float MeshLOD { get; private set; } | 94 | public float MeshLOD { get; private set; } |
@@ -112,6 +107,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
112 | private float m_fixedTimeStep; | 107 | private float m_fixedTimeStep; |
113 | private long m_simulationStep = 0; | 108 | private long m_simulationStep = 0; |
114 | public long SimulationStep { get { return m_simulationStep; } } | 109 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | ||
115 | 111 | ||
116 | // A value of the time now so all the collision and update routines do not have to get their own | 112 | // A value of the time now so all the collision and update routines do not have to get their own |
117 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 113 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
@@ -131,6 +127,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
131 | 127 | ||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | 128 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed |
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 129 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes |
130 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
134 | 131 | ||
135 | public float PID_D { get; private set; } // derivative | 132 | public float PID_D { get; private set; } // derivative |
136 | public float PID_P { get; private set; } // proportional | 133 | public float PID_P { get; private set; } // proportional |
@@ -254,19 +251,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
254 | 251 | ||
255 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 252 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're |
256 | // a child in a mega-region. | 253 | // a child in a mega-region. |
257 | // Turns out that Bullet really doesn't care about the extents of the simulated | 254 | // Bullet actually doesn't care about the extents of the simulated |
258 | // area. It tracks active objects no matter where they are. | 255 | // area. It tracks active objects no matter where they are. |
259 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 256 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
260 | 257 | ||
261 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 258 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); |
262 | WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | 259 | World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), |
263 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | 260 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), |
264 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | 261 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), |
265 | m_DebugLogCallbackHandle); | 262 | m_DebugLogCallbackHandle)); |
266 | |||
267 | // Initialization to support the transition to a new API which puts most of the logic | ||
268 | // into the C# code so it is easier to modify and add to. | ||
269 | World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID)); | ||
270 | 263 | ||
271 | Constraints = new BSConstraintCollection(World); | 264 | Constraints = new BSConstraintCollection(World); |
272 | 265 | ||
@@ -331,7 +324,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
331 | // Called directly from unmanaged code so don't do much | 324 | // Called directly from unmanaged code so don't do much |
332 | private void BulletLoggerPhysLog(string msg) | 325 | private void BulletLoggerPhysLog(string msg) |
333 | { | 326 | { |
334 | PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); | 327 | DetailLog("[BULLETS UNMANAGED]:" + msg); |
335 | } | 328 | } |
336 | 329 | ||
337 | public override void Dispose() | 330 | public override void Dispose() |
@@ -363,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
363 | } | 356 | } |
364 | 357 | ||
365 | // Anything left in the unmanaged code should be cleaned out | 358 | // Anything left in the unmanaged code should be cleaned out |
366 | BulletSimAPI.Shutdown(WorldID); | 359 | BulletSimAPI.Shutdown2(World.ptr); |
367 | 360 | ||
368 | // Not logging any more | 361 | // Not logging any more |
369 | PhysicsLogging.Close(); | 362 | PhysicsLogging.Close(); |
@@ -494,19 +487,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
494 | m_simulationStep++; | 487 | m_simulationStep++; |
495 | int numSubSteps = 0; | 488 | int numSubSteps = 0; |
496 | 489 | ||
497 | // Sometimes needed for debugging to find out what happened before the step | 490 | // DEBUG |
498 | // PhysicsLogging.Flush(); | 491 | // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep); |
499 | 492 | ||
500 | try | 493 | try |
501 | { | 494 | { |
502 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 495 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
503 | 496 | ||
504 | numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, | 497 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
505 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | 498 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); |
506 | 499 | ||
507 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 500 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
508 | DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}", | 501 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", |
509 | DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 502 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); |
510 | } | 503 | } |
511 | catch (Exception e) | 504 | catch (Exception e) |
512 | { | 505 | { |
@@ -539,26 +532,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
539 | } | 532 | } |
540 | } | 533 | } |
541 | 534 | ||
542 | // This is a kludge to get avatar movement updates. | ||
543 | // the simulator expects collisions for avatars even if there are have been no collisions. This updates | ||
544 | // avatar animations and stuff. | ||
545 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
546 | foreach (BSPhysObject bsp in m_avatars) | ||
547 | bsp.SendCollisions(); | ||
548 | |||
549 | // The above SendCollision's batch up the collisions on the objects. | 535 | // The above SendCollision's batch up the collisions on the objects. |
550 | // Now push the collisions into the simulator. | 536 | // Now push the collisions into the simulator. |
551 | if (ObjectsWithCollisions.Count > 0) | 537 | if (ObjectsWithCollisions.Count > 0) |
552 | { | 538 | { |
553 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | 539 | foreach (BSPhysObject bsp in ObjectsWithCollisions) |
554 | if (!m_avatars.Contains(bsp)) // don't call avatars twice | 540 | if (!bsp.SendCollisions()) |
555 | if (!bsp.SendCollisions()) | 541 | { |
556 | { | 542 | // If the object is done colliding, see that it's removed from the colliding list |
557 | // If the object is done colliding, see that it's removed from the colliding list | 543 | ObjectsWithNoMoreCollisions.Add(bsp); |
558 | ObjectsWithNoMoreCollisions.Add(bsp); | 544 | } |
559 | } | ||
560 | } | 545 | } |
561 | 546 | ||
547 | // This is a kludge to get avatar movement updates. | ||
548 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
549 | // The event updates avatar animations and stuff. | ||
550 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
551 | foreach (BSPhysObject bsp in m_avatars) | ||
552 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
553 | bsp.SendCollisions(); | ||
554 | |||
562 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 555 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
563 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 556 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
564 | if (ObjectsWithNoMoreCollisions.Count > 0) | 557 | if (ObjectsWithNoMoreCollisions.Count > 0) |
@@ -582,19 +575,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
582 | } | 575 | } |
583 | } | 576 | } |
584 | 577 | ||
585 | // If enabled, call into the physics engine to dump statistics | 578 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
586 | if (m_detailedStatsStep > 0) | 579 | // Only enable this in a limited test world with few objects. |
587 | { | 580 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG |
588 | if ((m_simulationStep % m_detailedStatsStep) == 0) | ||
589 | { | ||
590 | BulletSimAPI.DumpBulletStatistics(); | ||
591 | } | ||
592 | } | ||
593 | 581 | ||
594 | // The physics engine returns the number of milliseconds it simulated this call. | 582 | // The physics engine returns the number of milliseconds it simulated this call. |
595 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 583 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
596 | // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. | 584 | // We multiply by 55 to give a recognizable running rate (55 or less). |
597 | return numSubSteps * m_fixedTimeStep * 1000; | 585 | return numSubSteps * m_fixedTimeStep * 1000 * 55; |
586 | // return timeStep * 1000 * 55; | ||
598 | } | 587 | } |
599 | 588 | ||
600 | // Something has collided | 589 | // Something has collided |
@@ -617,7 +606,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
617 | BSPhysObject collidee = null; | 606 | BSPhysObject collidee = null; |
618 | PhysObjects.TryGetValue(collidingWith, out collidee); | 607 | PhysObjects.TryGetValue(collidingWith, out collidee); |
619 | 608 | ||
620 | DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | 609 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); |
621 | 610 | ||
622 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 611 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
623 | { | 612 | { |
@@ -704,6 +693,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
704 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process | 693 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process |
705 | { | 694 | { |
706 | // swizzle a new list into the list location so we can process what's there | 695 | // swizzle a new list into the list location so we can process what's there |
696 | int taintCount = m_taintsToProcessPerStep; | ||
697 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | ||
698 | while (_taintedObjects.Count > 0 && taintCount-- > 0) | ||
699 | { | ||
700 | bool gotOne = false; | ||
701 | lock (_taintLock) | ||
702 | { | ||
703 | if (_taintedObjects.Count > 0) | ||
704 | { | ||
705 | oneCallback = _taintedObjects[0]; | ||
706 | _taintedObjects.RemoveAt(0); | ||
707 | gotOne = true; | ||
708 | } | ||
709 | } | ||
710 | if (gotOne) | ||
711 | { | ||
712 | try | ||
713 | { | ||
714 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
715 | oneCallback.callback(); | ||
716 | } | ||
717 | catch (Exception e) | ||
718 | { | ||
719 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
720 | } | ||
721 | } | ||
722 | } | ||
723 | /* | ||
724 | // swizzle a new list into the list location so we can process what's there | ||
707 | List<TaintCallbackEntry> oldList; | 725 | List<TaintCallbackEntry> oldList; |
708 | lock (_taintLock) | 726 | lock (_taintLock) |
709 | { | 727 | { |
@@ -715,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
715 | { | 733 | { |
716 | try | 734 | try |
717 | { | 735 | { |
736 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
718 | tcbe.callback(); | 737 | tcbe.callback(); |
719 | } | 738 | } |
720 | catch (Exception e) | 739 | catch (Exception e) |
@@ -723,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
723 | } | 742 | } |
724 | } | 743 | } |
725 | oldList.Clear(); | 744 | oldList.Clear(); |
745 | */ | ||
726 | } | 746 | } |
727 | } | 747 | } |
728 | 748 | ||
@@ -780,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
780 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | 800 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); |
781 | delegate float ParamGet(BSScene scene); | 801 | delegate float ParamGet(BSScene scene); |
782 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | 802 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); |
803 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
783 | 804 | ||
784 | private struct ParameterDefn | 805 | private struct ParameterDefn |
785 | { | 806 | { |
@@ -789,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
789 | public ParamUser userParam; // get the value from the configuration file | 810 | public ParamUser userParam; // get the value from the configuration file |
790 | public ParamGet getter; // return the current value stored for this parameter | 811 | public ParamGet getter; // return the current value stored for this parameter |
791 | public ParamSet setter; // set the current value for this parameter | 812 | public ParamSet setter; // set the current value for this parameter |
813 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
792 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | 814 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) |
793 | { | 815 | { |
794 | name = n; | 816 | name = n; |
@@ -797,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
797 | userParam = u; | 819 | userParam = u; |
798 | getter = g; | 820 | getter = g; |
799 | setter = s; | 821 | setter = s; |
822 | onObject = null; | ||
823 | } | ||
824 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
825 | { | ||
826 | name = n; | ||
827 | desc = d; | ||
828 | defaultValue = v; | ||
829 | userParam = u; | ||
830 | getter = g; | ||
831 | setter = s; | ||
832 | onObject = o; | ||
800 | } | 833 | } |
801 | } | 834 | } |
802 | 835 | ||
@@ -818,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
818 | // | 851 | // |
819 | // The single letter parameters for the delegates are: | 852 | // The single letter parameters for the delegates are: |
820 | // s = BSScene | 853 | // s = BSScene |
854 | // o = BSPhysObject | ||
821 | // p = string parameter name | 855 | // p = string parameter name |
822 | // l = localID of referenced object | 856 | // l = localID of referenced object |
823 | // v = float value | 857 | // v = float value |
@@ -834,6 +868,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
834 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | 868 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, |
835 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | 869 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, |
836 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | 870 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), |
871 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
872 | ConfigurationParameters.numericTrue, | ||
873 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
874 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
875 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
837 | 876 | ||
838 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 877 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
839 | 8f, | 878 | 8f, |
@@ -876,6 +915,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
876 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | 915 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, |
877 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | 916 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, |
878 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | 917 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), |
918 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
919 | 100f, | ||
920 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
921 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
922 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
879 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | 923 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", |
880 | 10000.01f, | 924 | 10000.01f, |
881 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | 925 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, |
@@ -917,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
917 | -9.80665f, | 961 | -9.80665f, |
918 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | 962 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, |
919 | (s) => { return s.m_params[0].gravity; }, | 963 | (s) => { return s.m_params[0].gravity; }, |
920 | (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), | 964 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, |
965 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
921 | 966 | ||
922 | 967 | ||
923 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | 968 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", |
924 | 0f, | 969 | 0f, |
925 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | 970 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, |
926 | (s) => { return s.m_params[0].linearDamping; }, | 971 | (s) => { return s.m_params[0].linearDamping; }, |
927 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ), | 972 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, |
973 | (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ), | ||
928 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | 974 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |
929 | 0f, | 975 | 0f, |
930 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | 976 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, |
931 | (s) => { return s.m_params[0].angularDamping; }, | 977 | (s) => { return s.m_params[0].angularDamping; }, |
932 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ), | 978 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, |
979 | (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ), | ||
933 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | 980 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", |
934 | 0.2f, | 981 | 0.2f, |
935 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | 982 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, |
936 | (s) => { return s.m_params[0].deactivationTime; }, | 983 | (s) => { return s.m_params[0].deactivationTime; }, |
937 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ), | 984 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, |
985 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ), | ||
938 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | 986 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |
939 | 0.8f, | 987 | 0.8f, |
940 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | 988 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, |
941 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | 989 | (s) => { return s.m_params[0].linearSleepingThreshold; }, |
942 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), | 990 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, |
991 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ), | ||
943 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | 992 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |
944 | 1.0f, | 993 | 1.0f, |
945 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | 994 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, |
946 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | 995 | (s) => { return s.m_params[0].angularSleepingThreshold; }, |
947 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), | 996 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, |
997 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ), | ||
948 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | 998 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |
949 | 0f, // set to zero to disable | 999 | 0f, // set to zero to disable |
950 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | 1000 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, |
951 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | 1001 | (s) => { return s.m_params[0].ccdMotionThreshold; }, |
952 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), | 1002 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, |
1003 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ), | ||
953 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | 1004 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , |
954 | 0f, | 1005 | 0f, |
955 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | 1006 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, |
956 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | 1007 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, |
957 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), | 1008 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, |
1009 | (s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ), | ||
958 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | 1010 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , |
959 | 0.1f, | 1011 | 0.1f, |
960 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | 1012 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, |
961 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | 1013 | (s) => { return s.m_params[0].contactProcessingThreshold; }, |
962 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), | 1014 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, |
1015 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ), | ||
963 | 1016 | ||
964 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1017 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
965 | 0.5f, | 1018 | 0.5f, |
966 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1019 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
967 | (s) => { return s.m_params[0].terrainFriction; }, | 1020 | (s) => { return s.m_params[0].terrainFriction; }, |
968 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), | 1021 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), |
969 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | 1022 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , |
970 | 0.8f, | 1023 | 0.8f, |
971 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | 1024 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, |
972 | (s) => { return s.m_params[0].terrainHitFraction; }, | 1025 | (s) => { return s.m_params[0].terrainHitFraction; }, |
973 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), | 1026 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), |
974 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | 1027 | new ParameterDefn("TerrainRestitution", "Bouncyness" , |
975 | 0f, | 1028 | 0f, |
976 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1029 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
977 | (s) => { return s.m_params[0].terrainRestitution; }, | 1030 | (s) => { return s.m_params[0].terrainRestitution; }, |
978 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), | 1031 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), |
979 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1032 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
980 | 0.2f, | 1033 | 0.2f, |
981 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1034 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
982 | (s) => { return s.m_params[0].avatarFriction; }, | 1035 | (s) => { return s.m_params[0].avatarFriction; }, |
983 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1036 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1037 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1038 | 10f, | ||
1039 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1040 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1041 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
984 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | 1042 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |
985 | 60f, | 1043 | 60f, |
986 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | 1044 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, |
@@ -1070,12 +1128,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1070 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | 1128 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, |
1071 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | 1129 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), |
1072 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | 1130 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |
1073 | 0.1f, | 1131 | 0.001f, |
1074 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | 1132 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, |
1075 | (s) => { return s.m_params[0].linkConstraintCFM; }, | 1133 | (s) => { return s.m_params[0].linkConstraintCFM; }, |
1076 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | 1134 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), |
1077 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | 1135 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
1078 | 0.2f, | 1136 | 0.8f, |
1079 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | 1137 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, |
1080 | (s) => { return s.m_params[0].linkConstraintERP; }, | 1138 | (s) => { return s.m_params[0].linkConstraintERP; }, |
1081 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | 1139 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), |
@@ -1085,11 +1143,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1085 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | 1143 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, |
1086 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | 1144 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), |
1087 | 1145 | ||
1088 | new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", | 1146 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", |
1089 | 0f, | 1147 | 0f, |
1090 | (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, | 1148 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, |
1091 | (s) => { return (float)s.m_detailedStatsStep; }, | 1149 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, |
1092 | (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), | 1150 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), |
1093 | }; | 1151 | }; |
1094 | 1152 | ||
1095 | // Convert a boolean to our numeric true and false values | 1153 | // Convert a boolean to our numeric true and false values |
@@ -1197,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1197 | return ret; | 1255 | return ret; |
1198 | } | 1256 | } |
1199 | 1257 | ||
1200 | // check to see if we are updating a parameter for a particular or all of the prims | ||
1201 | protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val) | ||
1202 | { | ||
1203 | List<uint> operateOn; | ||
1204 | lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys); | ||
1205 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
1206 | } | ||
1207 | |||
1208 | // update all the localIDs specified | 1258 | // update all the localIDs specified |
1209 | // If the local ID is APPLY_TO_NONE, just change the default value | 1259 | // If the local ID is APPLY_TO_NONE, just change the default value |
1210 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | 1260 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |
1211 | // If the localID is a specific object, apply the parameter change to only that object | 1261 | // If the localID is a specific object, apply the parameter change to only that object |
1212 | protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) | 1262 | protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) |
1213 | { | 1263 | { |
1264 | List<uint> objectIDs = new List<uint>(); | ||
1214 | switch (localID) | 1265 | switch (localID) |
1215 | { | 1266 | { |
1216 | case PhysParameterEntry.APPLY_TO_NONE: | 1267 | case PhysParameterEntry.APPLY_TO_NONE: |
1217 | defaultLoc = val; // setting only the default value | 1268 | defaultLoc = val; // setting only the default value |
1269 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
1270 | objectIDs.Add(TERRAIN_ID); | ||
1271 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1218 | break; | 1272 | break; |
1219 | case PhysParameterEntry.APPLY_TO_ALL: | 1273 | case PhysParameterEntry.APPLY_TO_ALL: |
1220 | defaultLoc = val; // setting ALL also sets the default value | 1274 | defaultLoc = val; // setting ALL also sets the default value |
1221 | List<uint> objectIDs = lIDs; | 1275 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); |
1222 | string xparm = parm.ToLower(); | 1276 | TaintedUpdateParameter(parm, objectIDs, val); |
1223 | float xval = val; | ||
1224 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1225 | foreach (uint lID in objectIDs) | ||
1226 | { | ||
1227 | BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval); | ||
1228 | } | ||
1229 | }); | ||
1230 | break; | 1277 | break; |
1231 | default: | 1278 | default: |
1232 | // setting only one localID | 1279 | // setting only one localID |
1233 | TaintedUpdateParameter(parm, localID, val); | 1280 | objectIDs.Add(localID); |
1281 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1234 | break; | 1282 | break; |
1235 | } | 1283 | } |
1236 | } | 1284 | } |
1237 | 1285 | ||
1238 | // schedule the actual updating of the paramter to when the phys engine is not busy | 1286 | // schedule the actual updating of the paramter to when the phys engine is not busy |
1239 | protected void TaintedUpdateParameter(string parm, uint localID, float val) | 1287 | protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) |
1240 | { | 1288 | { |
1241 | uint xlocalID = localID; | ||
1242 | string xparm = parm.ToLower(); | ||
1243 | float xval = val; | 1289 | float xval = val; |
1244 | TaintedObject("BSScene.TaintedUpdateParameter", delegate() { | 1290 | List<uint> xlIDs = lIDs; |
1245 | BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval); | 1291 | string xparm = parm; |
1292 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1293 | ParameterDefn thisParam; | ||
1294 | if (TryGetParameter(xparm, out thisParam)) | ||
1295 | { | ||
1296 | if (thisParam.onObject != null) | ||
1297 | { | ||
1298 | foreach (uint lID in xlIDs) | ||
1299 | { | ||
1300 | BSPhysObject theObject = null; | ||
1301 | PhysObjects.TryGetValue(lID, out theObject); | ||
1302 | thisParam.onObject(this, theObject, xval); | ||
1303 | } | ||
1304 | } | ||
1305 | } | ||
1246 | }); | 1306 | }); |
1247 | } | 1307 | } |
1248 | 1308 | ||
@@ -1270,6 +1330,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1270 | public void DetailLog(string msg, params Object[] args) | 1330 | public void DetailLog(string msg, params Object[] args) |
1271 | { | 1331 | { |
1272 | PhysicsLogging.Write(msg, args); | 1332 | PhysicsLogging.Write(msg, args); |
1333 | // Add the Flush() if debugging crashes to get all the messages written out. | ||
1334 | // PhysicsLogging.Flush(); | ||
1273 | } | 1335 | } |
1274 | // used to fill in the LocalID when there isn't one | 1336 | // used to fill in the LocalID when there isn't one |
1275 | public const string DetailLogZero = "0000000000"; | 1337 | public const string DetailLogZero = "0000000000"; |