aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs232
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;
39using OpenMetaverse; 39using 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";