diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 748 |
1 files changed, 74 insertions, 674 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 2ca4912..e8e0d50 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -69,20 +69,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
69 | // every tick so OpenSim will update its animation. | 69 | // every tick so OpenSim will update its animation. |
70 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 70 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |
71 | 71 | ||
72 | // List of all the objects that have vehicle properties and should be called | ||
73 | // to update each physics step. | ||
74 | private List<BSPhysObject> m_vehicles = new List<BSPhysObject>(); | ||
75 | |||
76 | // let my minuions use my logger | 72 | // let my minuions use my logger |
77 | public ILog Logger { get { return m_log; } } | 73 | public ILog Logger { get { return m_log; } } |
78 | 74 | ||
79 | public IMesher mesher; | 75 | public IMesher mesher; |
80 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
81 | public float MeshLOD { get; private set; } | ||
82 | public float MeshMegaPrimLOD { get; private set; } | ||
83 | public float MeshMegaPrimThreshold { get; private set; } | ||
84 | public float SculptLOD { get; private set; } | ||
85 | |||
86 | public uint WorldID { get; private set; } | 76 | public uint WorldID { get; private set; } |
87 | public BulletSim World { get; private set; } | 77 | public BulletSim World { get; private set; } |
88 | 78 | ||
@@ -90,24 +80,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | public BSConstraintCollection Constraints { get; private set; } | 80 | public BSConstraintCollection Constraints { get; private set; } |
91 | 81 | ||
92 | // Simulation parameters | 82 | // Simulation parameters |
93 | private int m_maxSubSteps; | 83 | internal int m_maxSubSteps; |
94 | private float m_fixedTimeStep; | 84 | internal float m_fixedTimeStep; |
95 | private long m_simulationStep = 0; | 85 | internal long m_simulationStep = 0; |
96 | public long SimulationStep { get { return m_simulationStep; } } | 86 | public long SimulationStep { get { return m_simulationStep; } } |
97 | private int m_taintsToProcessPerStep; | 87 | internal int m_taintsToProcessPerStep; |
98 | 88 | internal float LastTimeStep { get; private set; } | |
99 | // Avatar parameters | ||
100 | public float ParamAvatarFriction { get; private set; } | ||
101 | public float ParamAvatarStandingFriction { get; private set; } | ||
102 | public float ParamAvatarDensity { get; private set; } | ||
103 | public float ParamAvatarRestitution { get; private set; } | ||
104 | public float ParamAvatarCapsuleWidth { get; private set; } | ||
105 | public float ParamAvatarCapsuleDepth { get; private set; } | ||
106 | public float ParamAvatarCapsuleHeight { get; private set; } | ||
107 | public float ParamAvatarContactProcessingThreshold { get; private set; } | ||
108 | 89 | ||
90 | // Physical objects can register for prestep or poststep events | ||
109 | public delegate void PreStepAction(float timeStep); | 91 | public delegate void PreStepAction(float timeStep); |
92 | public delegate void PostStepAction(float timeStep); | ||
110 | public event PreStepAction BeforeStep; | 93 | public event PreStepAction BeforeStep; |
94 | public event PreStepAction AfterStep; | ||
111 | 95 | ||
112 | // A value of the time now so all the collision and update routines do not have to get their own | 96 | // A value of the time now so all the collision and update routines do not have to get their own |
113 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 97 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
@@ -121,20 +105,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
121 | public bool InTaintTime { get; private set; } | 105 | public bool InTaintTime { get; private set; } |
122 | 106 | ||
123 | // Pinned memory used to pass step information between managed and unmanaged | 107 | // Pinned memory used to pass step information between managed and unmanaged |
124 | private int m_maxCollisionsPerFrame; | 108 | internal int m_maxCollisionsPerFrame; |
125 | private CollisionDesc[] m_collisionArray; | 109 | internal CollisionDesc[] m_collisionArray; |
126 | private GCHandle m_collisionArrayPinnedHandle; | 110 | internal GCHandle m_collisionArrayPinnedHandle; |
127 | |||
128 | private int m_maxUpdatesPerFrame; | ||
129 | private EntityProperties[] m_updateArray; | ||
130 | private GCHandle m_updateArrayPinnedHandle; | ||
131 | 111 | ||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | 112 | internal int m_maxUpdatesPerFrame; |
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 113 | internal EntityProperties[] m_updateArray; |
134 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | 114 | internal GCHandle m_updateArrayPinnedHandle; |
135 | |||
136 | public float PID_D { get; private set; } // derivative | ||
137 | public float PID_P { get; private set; } // proportional | ||
138 | 115 | ||
139 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | 116 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero |
140 | public const uint GROUNDPLANE_ID = 1; | 117 | public const uint GROUNDPLANE_ID = 1; |
@@ -145,7 +122,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
145 | 122 | ||
146 | public ConfigurationParameters Params | 123 | public ConfigurationParameters Params |
147 | { | 124 | { |
148 | get { return m_params[0]; } | 125 | get { return UnmanagedParams[0]; } |
149 | } | 126 | } |
150 | public Vector3 DefaultGravity | 127 | public Vector3 DefaultGravity |
151 | { | 128 | { |
@@ -157,8 +134,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
157 | get { return Params.gravity; } | 134 | get { return Params.gravity; } |
158 | } | 135 | } |
159 | 136 | ||
160 | public float MaximumObjectMass { get; private set; } | ||
161 | |||
162 | // When functions in the unmanaged code must be called, it is only | 137 | // When functions in the unmanaged code must be called, it is only |
163 | // done at a known time just before the simulation step. The taint | 138 | // done at a known time just before the simulation step. The taint |
164 | // system saves all these function calls and executes them in | 139 | // system saves all these function calls and executes them in |
@@ -181,7 +156,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
181 | 156 | ||
182 | // A pointer to an instance if this structure is passed to the C++ code | 157 | // A pointer to an instance if this structure is passed to the C++ code |
183 | // Used to pass basic configuration values to the unmanaged code. | 158 | // Used to pass basic configuration values to the unmanaged code. |
184 | ConfigurationParameters[] m_params; | 159 | internal ConfigurationParameters[] UnmanagedParams; |
185 | GCHandle m_paramsHandle; | 160 | GCHandle m_paramsHandle; |
186 | 161 | ||
187 | // Handle to the callback used by the unmanaged code to call into the managed code. | 162 | // Handle to the callback used by the unmanaged code to call into the managed code. |
@@ -218,8 +193,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
218 | Shapes = new BSShapeCollection(this); | 193 | Shapes = new BSShapeCollection(this); |
219 | 194 | ||
220 | // Allocate pinned memory to pass parameters. | 195 | // Allocate pinned memory to pass parameters. |
221 | m_params = new ConfigurationParameters[1]; | 196 | UnmanagedParams = new ConfigurationParameters[1]; |
222 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); | 197 | m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned); |
223 | 198 | ||
224 | // Set default values for physics parameters plus any overrides from the ini file | 199 | // Set default values for physics parameters plus any overrides from the ini file |
225 | GetInitialParameterValues(config); | 200 | GetInitialParameterValues(config); |
@@ -277,7 +252,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
277 | TerrainManager = new BSTerrainManager(this); | 252 | TerrainManager = new BSTerrainManager(this); |
278 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 253 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
279 | 254 | ||
280 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); | 255 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); |
281 | 256 | ||
282 | InTaintTime = false; | 257 | InTaintTime = false; |
283 | m_initialized = true; | 258 | m_initialized = true; |
@@ -288,9 +263,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
288 | private void GetInitialParameterValues(IConfigSource config) | 263 | private void GetInitialParameterValues(IConfigSource config) |
289 | { | 264 | { |
290 | ConfigurationParameters parms = new ConfigurationParameters(); | 265 | ConfigurationParameters parms = new ConfigurationParameters(); |
291 | m_params[0] = parms; | 266 | UnmanagedParams[0] = parms; |
292 | 267 | ||
293 | SetParameterDefaultValues(); | 268 | BSParam.SetParameterDefaultValues(this); |
294 | 269 | ||
295 | if (config != null) | 270 | if (config != null) |
296 | { | 271 | { |
@@ -298,7 +273,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
298 | IConfig pConfig = config.Configs["BulletSim"]; | 273 | IConfig pConfig = config.Configs["BulletSim"]; |
299 | if (pConfig != null) | 274 | if (pConfig != null) |
300 | { | 275 | { |
301 | SetParameterConfigurationValues(pConfig); | 276 | BSParam.SetParameterConfigurationValues(this, pConfig); |
302 | 277 | ||
303 | // Very detailed logging for physics debugging | 278 | // Very detailed logging for physics debugging |
304 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | 279 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |
@@ -492,6 +467,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
492 | // Simulate one timestep | 467 | // Simulate one timestep |
493 | public override float Simulate(float timeStep) | 468 | public override float Simulate(float timeStep) |
494 | { | 469 | { |
470 | // prevent simulation until we've been initialized | ||
471 | if (!m_initialized) return 5.0f; | ||
472 | |||
473 | LastTimeStep = timeStep; | ||
474 | |||
495 | int updatedEntityCount = 0; | 475 | int updatedEntityCount = 0; |
496 | IntPtr updatedEntitiesPtr; | 476 | IntPtr updatedEntitiesPtr; |
497 | int collidersCount = 0; | 477 | int collidersCount = 0; |
@@ -500,26 +480,27 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
500 | int beforeTime = 0; | 480 | int beforeTime = 0; |
501 | int simTime = 0; | 481 | int simTime = 0; |
502 | 482 | ||
503 | // prevent simulation until we've been initialized | ||
504 | if (!m_initialized) return 5.0f; | ||
505 | |||
506 | // update the prim states while we know the physics engine is not busy | 483 | // update the prim states while we know the physics engine is not busy |
507 | int numTaints = _taintOperations.Count; | 484 | int numTaints = _taintOperations.Count; |
485 | |||
486 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
487 | |||
508 | ProcessTaints(); | 488 | ProcessTaints(); |
509 | 489 | ||
510 | // Some of the prims operate with special vehicle properties | 490 | // Some of the physical objects requre individual, pre-step calls |
511 | DoPreStepActions(timeStep); | 491 | TriggerPreStepEvent(timeStep); |
512 | 492 | ||
513 | // the prestep actions might have added taints | 493 | // the prestep actions might have added taints |
514 | ProcessTaints(); | 494 | ProcessTaints(); |
515 | 495 | ||
496 | InTaintTime = false; // Only used for debugging so locking is not necessary. | ||
497 | |||
516 | // step the physical world one interval | 498 | // step the physical world one interval |
517 | m_simulationStep++; | 499 | m_simulationStep++; |
518 | int numSubSteps = 0; | 500 | int numSubSteps = 0; |
519 | 501 | ||
520 | try | 502 | try |
521 | { | 503 | { |
522 | if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG | ||
523 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 504 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
524 | 505 | ||
525 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 506 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
@@ -529,7 +510,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
529 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | 510 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |
530 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | 511 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, |
531 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | 512 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); |
532 | if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG | ||
533 | } | 513 | } |
534 | catch (Exception e) | 514 | catch (Exception e) |
535 | { | 515 | { |
@@ -608,7 +588,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
608 | } | 588 | } |
609 | } | 589 | } |
610 | 590 | ||
611 | ProcessPostStepTaints(); | 591 | TriggerPostStepEvent(timeStep); |
612 | 592 | ||
613 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 593 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
614 | // Only enable this in a limited test world with few objects. | 594 | // Only enable this in a limited test world with few objects. |
@@ -700,6 +680,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
700 | public override bool IsThreaded { get { return false; } } | 680 | public override bool IsThreaded { get { return false; } } |
701 | 681 | ||
702 | #region Taints | 682 | #region Taints |
683 | // The simulation execution order is: | ||
684 | // Simulate() | ||
685 | // DoOneTimeTaints | ||
686 | // TriggerPreStepEvent | ||
687 | // DoOneTimeTaints | ||
688 | // Step() | ||
689 | // ProcessAndForwardCollisions | ||
690 | // ProcessAndForwardPropertyUpdates | ||
691 | // TriggerPostStepEvent | ||
703 | 692 | ||
704 | // Calls to the PhysicsActors can't directly call into the physics engine | 693 | // Calls to the PhysicsActors can't directly call into the physics engine |
705 | // because it might be busy. We delay changes to a known time. | 694 | // because it might be busy. We delay changes to a known time. |
@@ -726,58 +715,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
726 | TaintedObject(ident, callback); | 715 | TaintedObject(ident, callback); |
727 | } | 716 | } |
728 | 717 | ||
718 | private void TriggerPreStepEvent(float timeStep) | ||
719 | { | ||
720 | PreStepAction actions = BeforeStep; | ||
721 | if (actions != null) | ||
722 | actions(timeStep); | ||
723 | |||
724 | } | ||
725 | |||
726 | private void TriggerPostStepEvent(float timeStep) | ||
727 | { | ||
728 | PreStepAction actions = AfterStep; | ||
729 | if (actions != null) | ||
730 | actions(timeStep); | ||
731 | |||
732 | } | ||
733 | |||
729 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | 734 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues |
730 | // a callback into itself to do the actual property change. That callback is called | 735 | // a callback into itself to do the actual property change. That callback is called |
731 | // here just before the physics engine is called to step the simulation. | 736 | // here just before the physics engine is called to step the simulation. |
732 | public void ProcessTaints() | 737 | public void ProcessTaints() |
733 | { | 738 | { |
734 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
735 | ProcessRegularTaints(); | 739 | ProcessRegularTaints(); |
736 | ProcessPostTaintTaints(); | 740 | ProcessPostTaintTaints(); |
737 | InTaintTime = false; | ||
738 | } | 741 | } |
739 | 742 | ||
740 | private void ProcessRegularTaints() | 743 | private void ProcessRegularTaints() |
741 | { | 744 | { |
742 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | 745 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process |
743 | { | 746 | { |
744 | /* | ||
745 | // Code to limit the number of taints processed per step. Meant to limit step time. | ||
746 | // Unsure if a good idea as code assumes that taints are done before the step. | ||
747 | int taintCount = m_taintsToProcessPerStep; | ||
748 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | ||
749 | while (_taintOperations.Count > 0 && taintCount-- > 0) | ||
750 | { | ||
751 | bool gotOne = false; | ||
752 | lock (_taintLock) | ||
753 | { | ||
754 | if (_taintOperations.Count > 0) | ||
755 | { | ||
756 | oneCallback = _taintOperations[0]; | ||
757 | _taintOperations.RemoveAt(0); | ||
758 | gotOne = true; | ||
759 | } | ||
760 | } | ||
761 | if (gotOne) | ||
762 | { | ||
763 | try | ||
764 | { | ||
765 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); | ||
766 | oneCallback.callback(); | ||
767 | } | ||
768 | catch (Exception e) | ||
769 | { | ||
770 | DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
771 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
772 | } | ||
773 | } | ||
774 | } | ||
775 | if (_taintOperations.Count > 0) | ||
776 | { | ||
777 | DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); | ||
778 | } | ||
779 | */ | ||
780 | |||
781 | // swizzle a new list into the list location so we can process what's there | 747 | // swizzle a new list into the list location so we can process what's there |
782 | List<TaintCallbackEntry> oldList; | 748 | List<TaintCallbackEntry> oldList; |
783 | lock (_taintLock) | 749 | lock (_taintLock) |
@@ -816,6 +782,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
816 | return; | 782 | return; |
817 | } | 783 | } |
818 | 784 | ||
785 | // Taints that happen after the normal taint processing but before the simulation step. | ||
819 | private void ProcessPostTaintTaints() | 786 | private void ProcessPostTaintTaints() |
820 | { | 787 | { |
821 | if (_postTaintOperations.Count > 0) | 788 | if (_postTaintOperations.Count > 0) |
@@ -843,45 +810,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
843 | } | 810 | } |
844 | } | 811 | } |
845 | 812 | ||
846 | public void PostStepTaintObject(String ident, TaintCallback callback) | ||
847 | { | ||
848 | if (!m_initialized) return; | ||
849 | |||
850 | lock (_taintLock) | ||
851 | { | ||
852 | _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
853 | } | ||
854 | |||
855 | return; | ||
856 | } | ||
857 | |||
858 | private void ProcessPostStepTaints() | ||
859 | { | ||
860 | if (_postStepOperations.Count > 0) | ||
861 | { | ||
862 | List<TaintCallbackEntry> oldList; | ||
863 | lock (_taintLock) | ||
864 | { | ||
865 | oldList = _postStepOperations; | ||
866 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
867 | } | ||
868 | |||
869 | foreach (TaintCallbackEntry tcbe in oldList) | ||
870 | { | ||
871 | try | ||
872 | { | ||
873 | DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
874 | tcbe.callback(); | ||
875 | } | ||
876 | catch (Exception e) | ||
877 | { | ||
878 | m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
879 | } | ||
880 | } | ||
881 | oldList.Clear(); | ||
882 | } | ||
883 | } | ||
884 | |||
885 | // Only used for debugging. Does not change state of anything so locking is not necessary. | 813 | // Only used for debugging. Does not change state of anything so locking is not necessary. |
886 | public bool AssertInTaintTime(string whereFrom) | 814 | public bool AssertInTaintTime(string whereFrom) |
887 | { | 815 | { |
@@ -889,540 +817,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
889 | { | 817 | { |
890 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | 818 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); |
891 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | 819 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); |
892 | Util.PrintCallStack(); // Prints the stack into the DEBUG log file. | 820 | Util.PrintCallStack(DetailLog); |
893 | } | 821 | } |
894 | return InTaintTime; | 822 | return InTaintTime; |
895 | } | 823 | } |
896 | 824 | ||
897 | #endregion // Taints | 825 | #endregion // Taints |
898 | 826 | ||
899 | #region Vehicles | ||
900 | |||
901 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) | ||
902 | { | ||
903 | RemoveVehiclePrim(vehic); | ||
904 | if (newType != Vehicle.TYPE_NONE) | ||
905 | { | ||
906 | // make it so the scene will call us each tick to do vehicle things | ||
907 | AddVehiclePrim(vehic); | ||
908 | } | ||
909 | } | ||
910 | |||
911 | // Make so the scene will call this prim for vehicle actions each tick. | ||
912 | // Safe to call if prim is already in the vehicle list. | ||
913 | public void AddVehiclePrim(BSPrim vehicle) | ||
914 | { | ||
915 | lock (m_vehicles) | ||
916 | { | ||
917 | if (!m_vehicles.Contains(vehicle)) | ||
918 | { | ||
919 | m_vehicles.Add(vehicle); | ||
920 | } | ||
921 | } | ||
922 | } | ||
923 | |||
924 | // Remove a prim from our list of vehicles. | ||
925 | // Safe to call if the prim is not in the vehicle list. | ||
926 | public void RemoveVehiclePrim(BSPrim vehicle) | ||
927 | { | ||
928 | lock (m_vehicles) | ||
929 | { | ||
930 | if (m_vehicles.Contains(vehicle)) | ||
931 | { | ||
932 | m_vehicles.Remove(vehicle); | ||
933 | } | ||
934 | } | ||
935 | } | ||
936 | |||
937 | private void DoPreStepActions(float timeStep) | ||
938 | { | ||
939 | ProcessVehicles(timeStep); | ||
940 | |||
941 | PreStepAction actions = BeforeStep; | ||
942 | if (actions != null) | ||
943 | actions(timeStep); | ||
944 | |||
945 | } | ||
946 | |||
947 | // Some prims have extra vehicle actions | ||
948 | // Called at taint time! | ||
949 | private void ProcessVehicles(float timeStep) | ||
950 | { | ||
951 | foreach (BSPhysObject pobj in m_vehicles) | ||
952 | { | ||
953 | pobj.StepVehicle(timeStep); | ||
954 | } | ||
955 | } | ||
956 | #endregion Vehicles | ||
957 | |||
958 | #region INI and command line parameter processing | 827 | #region INI and command line parameter processing |
959 | 828 | ||
960 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | ||
961 | delegate float ParamGet(BSScene scene); | ||
962 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||
963 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
964 | |||
965 | private struct ParameterDefn | ||
966 | { | ||
967 | public string name; // string name of the parameter | ||
968 | public string desc; // a short description of what the parameter means | ||
969 | public float defaultValue; // default value if not specified anywhere else | ||
970 | public ParamUser userParam; // get the value from the configuration file | ||
971 | public ParamGet getter; // return the current value stored for this parameter | ||
972 | public ParamSet setter; // set the current value for this parameter | ||
973 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
974 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | ||
975 | { | ||
976 | name = n; | ||
977 | desc = d; | ||
978 | defaultValue = v; | ||
979 | userParam = u; | ||
980 | getter = g; | ||
981 | setter = s; | ||
982 | onObject = null; | ||
983 | } | ||
984 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
985 | { | ||
986 | name = n; | ||
987 | desc = d; | ||
988 | defaultValue = v; | ||
989 | userParam = u; | ||
990 | getter = g; | ||
991 | setter = s; | ||
992 | onObject = o; | ||
993 | } | ||
994 | } | ||
995 | |||
996 | // List of all of the externally visible parameters. | ||
997 | // For each parameter, this table maps a text name to getter and setters. | ||
998 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
999 | // location somewhere in the program and make an entry in this table with the | ||
1000 | // getters and setters. | ||
1001 | // It is easiest to find an existing definition and copy it. | ||
1002 | // Parameter values are floats. Booleans are converted to a floating value. | ||
1003 | // | ||
1004 | // A ParameterDefn() takes the following parameters: | ||
1005 | // -- the text name of the parameter. This is used for console input and ini file. | ||
1006 | // -- a short text description of the parameter. This shows up in the console listing. | ||
1007 | // -- a delegate for fetching the parameter from the ini file. | ||
1008 | // Should handle fetching the right type from the ini file and converting it. | ||
1009 | // -- a delegate for getting the value as a float | ||
1010 | // -- a delegate for setting the value from a float | ||
1011 | // -- an optional delegate to update the value in the world. Most often used to | ||
1012 | // push the new value to an in-world object. | ||
1013 | // | ||
1014 | // The single letter parameters for the delegates are: | ||
1015 | // s = BSScene | ||
1016 | // o = BSPhysObject | ||
1017 | // p = string parameter name | ||
1018 | // l = localID of referenced object | ||
1019 | // v = float value | ||
1020 | // cf = parameter configuration class (for fetching values from ini file) | ||
1021 | private ParameterDefn[] ParameterDefinitions = | ||
1022 | { | ||
1023 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
1024 | ConfigurationParameters.numericTrue, | ||
1025 | (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1026 | (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); }, | ||
1027 | (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ), | ||
1028 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
1029 | ConfigurationParameters.numericFalse, | ||
1030 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1031 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | ||
1032 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | ||
1033 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
1034 | ConfigurationParameters.numericTrue, | ||
1035 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1036 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
1037 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
1038 | |||
1039 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
1040 | 8f, | ||
1041 | (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); }, | ||
1042 | (s) => { return s.MeshLOD; }, | ||
1043 | (s,p,l,v) => { s.MeshLOD = v; } ), | ||
1044 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
1045 | 16f, | ||
1046 | (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
1047 | (s) => { return s.MeshMegaPrimLOD; }, | ||
1048 | (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ), | ||
1049 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
1050 | 10f, | ||
1051 | (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
1052 | (s) => { return s.MeshMegaPrimThreshold; }, | ||
1053 | (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ), | ||
1054 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
1055 | 32f, | ||
1056 | (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||
1057 | (s) => { return s.SculptLOD; }, | ||
1058 | (s,p,l,v) => { s.SculptLOD = v; } ), | ||
1059 | |||
1060 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | ||
1061 | 10f, | ||
1062 | (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | ||
1063 | (s) => { return (float)s.m_maxSubSteps; }, | ||
1064 | (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | ||
1065 | new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
1066 | 1f / 60f, | ||
1067 | (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | ||
1068 | (s) => { return (float)s.m_fixedTimeStep; }, | ||
1069 | (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | ||
1070 | new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
1071 | 2048f, | ||
1072 | (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | ||
1073 | (s) => { return (float)s.m_maxCollisionsPerFrame; }, | ||
1074 | (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
1075 | new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
1076 | 8000f, | ||
1077 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | ||
1078 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | ||
1079 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
1080 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
1081 | 500f, | ||
1082 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
1083 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
1084 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
1085 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||
1086 | 10000.01f, | ||
1087 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | ||
1088 | (s) => { return (float)s.MaximumObjectMass; }, | ||
1089 | (s,p,l,v) => { s.MaximumObjectMass = v; } ), | ||
1090 | |||
1091 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | ||
1092 | 2200f, | ||
1093 | (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); }, | ||
1094 | (s) => { return (float)s.PID_D; }, | ||
1095 | (s,p,l,v) => { s.PID_D = v; } ), | ||
1096 | new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | ||
1097 | 900f, | ||
1098 | (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); }, | ||
1099 | (s) => { return (float)s.PID_P; }, | ||
1100 | (s,p,l,v) => { s.PID_P = v; } ), | ||
1101 | |||
1102 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | ||
1103 | 0.2f, | ||
1104 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, | ||
1105 | (s) => { return s.m_params[0].defaultFriction; }, | ||
1106 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), | ||
1107 | new ParameterDefn("DefaultDensity", "Density for new objects" , | ||
1108 | 10.000006836f, // Aluminum g/cm3 | ||
1109 | (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); }, | ||
1110 | (s) => { return s.m_params[0].defaultDensity; }, | ||
1111 | (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ), | ||
1112 | new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||
1113 | 0f, | ||
1114 | (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); }, | ||
1115 | (s) => { return s.m_params[0].defaultRestitution; }, | ||
1116 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), | ||
1117 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
1118 | 0.04f, | ||
1119 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, | ||
1120 | (s) => { return s.m_params[0].collisionMargin; }, | ||
1121 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), | ||
1122 | new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||
1123 | -9.80665f, | ||
1124 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | ||
1125 | (s) => { return s.m_params[0].gravity; }, | ||
1126 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | ||
1127 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
1128 | |||
1129 | |||
1130 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
1131 | 0f, | ||
1132 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | ||
1133 | (s) => { return s.m_params[0].linearDamping; }, | ||
1134 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, | ||
1135 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ), | ||
1136 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
1137 | 0f, | ||
1138 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | ||
1139 | (s) => { return s.m_params[0].angularDamping; }, | ||
1140 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, | ||
1141 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ), | ||
1142 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | ||
1143 | 0.2f, | ||
1144 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | ||
1145 | (s) => { return s.m_params[0].deactivationTime; }, | ||
1146 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, | ||
1147 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||
1148 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
1149 | 0.8f, | ||
1150 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | ||
1151 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | ||
1152 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, | ||
1153 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1154 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
1155 | 1.0f, | ||
1156 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | ||
1157 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | ||
1158 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, | ||
1159 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1160 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
1161 | 0f, // set to zero to disable | ||
1162 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | ||
1163 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | ||
1164 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, | ||
1165 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||
1166 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
1167 | 0f, | ||
1168 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | ||
1169 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | ||
1170 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, | ||
1171 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||
1172 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | ||
1173 | 0.1f, | ||
1174 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | ||
1175 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | ||
1176 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | ||
1177 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||
1178 | |||
1179 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
1180 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||
1181 | (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); }, | ||
1182 | (s) => { return s.m_params[0].terrainImplementation; }, | ||
1183 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | ||
1184 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
1185 | 0.3f, | ||
1186 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | ||
1187 | (s) => { return s.m_params[0].terrainFriction; }, | ||
1188 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | ||
1189 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | ||
1190 | 0.8f, | ||
1191 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | ||
1192 | (s) => { return s.m_params[0].terrainHitFraction; }, | ||
1193 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
1194 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | ||
1195 | 0f, | ||
1196 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | ||
1197 | (s) => { return s.m_params[0].terrainRestitution; }, | ||
1198 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
1199 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
1200 | 0.04f, | ||
1201 | (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); }, | ||
1202 | (s) => { return s.m_params[0].terrainCollisionMargin; }, | ||
1203 | (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
1204 | |||
1205 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
1206 | 0.2f, | ||
1207 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | ||
1208 | (s) => { return s.m_params[0].avatarFriction; }, | ||
1209 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | ||
1210 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1211 | 10.0f, | ||
1212 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1213 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1214 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
1215 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
1216 | 60f, | ||
1217 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | ||
1218 | (s) => { return s.m_params[0].avatarDensity; }, | ||
1219 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ), | ||
1220 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
1221 | 0f, | ||
1222 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, | ||
1223 | (s) => { return s.m_params[0].avatarRestitution; }, | ||
1224 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), | ||
1225 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
1226 | 0.6f, | ||
1227 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); }, | ||
1228 | (s) => { return s.m_params[0].avatarCapsuleWidth; }, | ||
1229 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ), | ||
1230 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
1231 | 0.45f, | ||
1232 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); }, | ||
1233 | (s) => { return s.m_params[0].avatarCapsuleDepth; }, | ||
1234 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ), | ||
1235 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | ||
1236 | 1.5f, | ||
1237 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, | ||
1238 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, | ||
1239 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), | ||
1240 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
1241 | 0.1f, | ||
1242 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
1243 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | ||
1244 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | ||
1245 | |||
1246 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
1247 | 0.95f, | ||
1248 | (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, | ||
1249 | (s) => { return s.m_params[0].vehicleAngularDamping; }, | ||
1250 | (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), | ||
1251 | |||
1252 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
1253 | 0f, | ||
1254 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | ||
1255 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, | ||
1256 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), | ||
1257 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
1258 | 0f, | ||
1259 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | ||
1260 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, | ||
1261 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
1262 | new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
1263 | ConfigurationParameters.numericFalse, | ||
1264 | (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1265 | (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; }, | ||
1266 | (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||
1267 | new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
1268 | ConfigurationParameters.numericFalse, | ||
1269 | (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1270 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, | ||
1271 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), | ||
1272 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
1273 | ConfigurationParameters.numericTrue, | ||
1274 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1275 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, | ||
1276 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), | ||
1277 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
1278 | ConfigurationParameters.numericTrue, | ||
1279 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1280 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, | ||
1281 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), | ||
1282 | new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
1283 | ConfigurationParameters.numericFalse, | ||
1284 | (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1285 | (s) => { return s.m_params[0].shouldEnableFrictionCaching; }, | ||
1286 | (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ), | ||
1287 | new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
1288 | 0f, // zero says use Bullet default | ||
1289 | (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||
1290 | (s) => { return s.m_params[0].numberOfSolverIterations; }, | ||
1291 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), | ||
1292 | |||
1293 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
1294 | (float)BSLinkset.LinksetImplementation.Compound, | ||
1295 | (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, | ||
1296 | (s) => { return s.m_params[0].linksetImplementation; }, | ||
1297 | (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), | ||
1298 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
1299 | ConfigurationParameters.numericFalse, | ||
1300 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1301 | (s) => { return s.m_params[0].linkConstraintUseFrameOffset; }, | ||
1302 | (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ), | ||
1303 | new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
1304 | ConfigurationParameters.numericTrue, | ||
1305 | (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1306 | (s) => { return s.m_params[0].linkConstraintEnableTransMotor; }, | ||
1307 | (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ), | ||
1308 | new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
1309 | 5.0f, | ||
1310 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||
1311 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; }, | ||
1312 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ), | ||
1313 | new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
1314 | 0.1f, | ||
1315 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||
1316 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | ||
1317 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | ||
1318 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
1319 | 0.1f, | ||
1320 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | ||
1321 | (s) => { return s.m_params[0].linkConstraintCFM; }, | ||
1322 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | ||
1323 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
1324 | 0.1f, | ||
1325 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | ||
1326 | (s) => { return s.m_params[0].linkConstraintERP; }, | ||
1327 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | ||
1328 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
1329 | 40, | ||
1330 | (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
1331 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | ||
1332 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | ||
1333 | |||
1334 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | ||
1335 | 0f, | ||
1336 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | ||
1337 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, | ||
1338 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), | ||
1339 | }; | ||
1340 | |||
1341 | // Convert a boolean to our numeric true and false values | ||
1342 | public float NumericBool(bool b) | ||
1343 | { | ||
1344 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
1345 | } | ||
1346 | |||
1347 | // Convert numeric true and false values to a boolean | ||
1348 | public bool BoolNumeric(float b) | ||
1349 | { | ||
1350 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
1351 | } | ||
1352 | |||
1353 | // Search through the parameter definitions and return the matching | ||
1354 | // ParameterDefn structure. | ||
1355 | // Case does not matter as names are compared after converting to lower case. | ||
1356 | // Returns 'false' if the parameter is not found. | ||
1357 | private bool TryGetParameter(string paramName, out ParameterDefn defn) | ||
1358 | { | ||
1359 | bool ret = false; | ||
1360 | ParameterDefn foundDefn = new ParameterDefn(); | ||
1361 | string pName = paramName.ToLower(); | ||
1362 | |||
1363 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1364 | { | ||
1365 | if (pName == parm.name.ToLower()) | ||
1366 | { | ||
1367 | foundDefn = parm; | ||
1368 | ret = true; | ||
1369 | break; | ||
1370 | } | ||
1371 | } | ||
1372 | defn = foundDefn; | ||
1373 | return ret; | ||
1374 | } | ||
1375 | |||
1376 | // Pass through the settable parameters and set the default values | ||
1377 | private void SetParameterDefaultValues() | ||
1378 | { | ||
1379 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1380 | { | ||
1381 | parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | // Get user set values out of the ini file. | ||
1386 | private void SetParameterConfigurationValues(IConfig cfg) | ||
1387 | { | ||
1388 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1389 | { | ||
1390 | parm.userParam(this, cfg, parm.name, parm.defaultValue); | ||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
1395 | |||
1396 | // This creates an array in the correct format for returning the list of | ||
1397 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
1398 | private void BuildParameterTable() | ||
1399 | { | ||
1400 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
1401 | { | ||
1402 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
1403 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
1404 | { | ||
1405 | ParameterDefn pd = ParameterDefinitions[ii]; | ||
1406 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
1407 | } | ||
1408 | |||
1409 | // make the list in alphabetical order for estetic reasons | ||
1410 | entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | ||
1411 | { | ||
1412 | return ppe1.name.CompareTo(ppe2.name); | ||
1413 | }); | ||
1414 | |||
1415 | SettableParameters = entries.ToArray(); | ||
1416 | } | ||
1417 | } | ||
1418 | |||
1419 | |||
1420 | #region IPhysicsParameters | 829 | #region IPhysicsParameters |
1421 | // Get the list of parameters this physics engine supports | 830 | // Get the list of parameters this physics engine supports |
1422 | public PhysParameterEntry[] GetParameterList() | 831 | public PhysParameterEntry[] GetParameterList() |
1423 | { | 832 | { |
1424 | BuildParameterTable(); | 833 | BSParam.BuildParameterTable(); |
1425 | return SettableParameters; | 834 | return BSParam.SettableParameters; |
1426 | } | 835 | } |
1427 | 836 | ||
1428 | // Set parameter on a specific or all instances. | 837 | // Set parameter on a specific or all instances. |
@@ -1434,8 +843,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1434 | public bool SetPhysicsParameter(string parm, float val, uint localID) | 843 | public bool SetPhysicsParameter(string parm, float val, uint localID) |
1435 | { | 844 | { |
1436 | bool ret = false; | 845 | bool ret = false; |
1437 | ParameterDefn theParam; | 846 | BSParam.ParameterDefn theParam; |
1438 | if (TryGetParameter(parm, out theParam)) | 847 | if (BSParam.TryGetParameter(parm, out theParam)) |
1439 | { | 848 | { |
1440 | theParam.setter(this, parm, localID, val); | 849 | theParam.setter(this, parm, localID, val); |
1441 | ret = true; | 850 | ret = true; |
@@ -1447,19 +856,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1447 | // If the local ID is APPLY_TO_NONE, just change the default value | 856 | // If the local ID is APPLY_TO_NONE, just change the default value |
1448 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | 857 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |
1449 | // If the localID is a specific object, apply the parameter change to only that object | 858 | // If the localID is a specific object, apply the parameter change to only that object |
1450 | private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) | 859 | internal delegate void AssignVal(float x); |
860 | internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) | ||
1451 | { | 861 | { |
1452 | List<uint> objectIDs = new List<uint>(); | 862 | List<uint> objectIDs = new List<uint>(); |
1453 | switch (localID) | 863 | switch (localID) |
1454 | { | 864 | { |
1455 | case PhysParameterEntry.APPLY_TO_NONE: | 865 | case PhysParameterEntry.APPLY_TO_NONE: |
1456 | defaultLoc = val; // setting only the default value | 866 | setDefault(val); // setting only the default value |
1457 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | 867 | // This will cause a call into the physical world if some operation is specified (SetOnObject). |
1458 | objectIDs.Add(TERRAIN_ID); | 868 | objectIDs.Add(TERRAIN_ID); |
1459 | TaintedUpdateParameter(parm, objectIDs, val); | 869 | TaintedUpdateParameter(parm, objectIDs, val); |
1460 | break; | 870 | break; |
1461 | case PhysParameterEntry.APPLY_TO_ALL: | 871 | case PhysParameterEntry.APPLY_TO_ALL: |
1462 | defaultLoc = val; // setting ALL also sets the default value | 872 | setDefault(val); // setting ALL also sets the default value |
1463 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | 873 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); |
1464 | TaintedUpdateParameter(parm, objectIDs, val); | 874 | TaintedUpdateParameter(parm, objectIDs, val); |
1465 | break; | 875 | break; |
@@ -1478,8 +888,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1478 | List<uint> xlIDs = lIDs; | 888 | List<uint> xlIDs = lIDs; |
1479 | string xparm = parm; | 889 | string xparm = parm; |
1480 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | 890 | TaintedObject("BSScene.UpdateParameterSet", delegate() { |
1481 | ParameterDefn thisParam; | 891 | BSParam.ParameterDefn thisParam; |
1482 | if (TryGetParameter(xparm, out thisParam)) | 892 | if (BSParam.TryGetParameter(xparm, out thisParam)) |
1483 | { | 893 | { |
1484 | if (thisParam.onObject != null) | 894 | if (thisParam.onObject != null) |
1485 | { | 895 | { |
@@ -1500,8 +910,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1500 | { | 910 | { |
1501 | float val = 0f; | 911 | float val = 0f; |
1502 | bool ret = false; | 912 | bool ret = false; |
1503 | ParameterDefn theParam; | 913 | BSParam.ParameterDefn theParam; |
1504 | if (TryGetParameter(parm, out theParam)) | 914 | if (BSParam.TryGetParameter(parm, out theParam)) |
1505 | { | 915 | { |
1506 | val = theParam.getter(this); | 916 | val = theParam.getter(this); |
1507 | ret = true; | 917 | ret = true; |
@@ -1514,16 +924,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1514 | 924 | ||
1515 | #endregion Runtime settable parameters | 925 | #endregion Runtime settable parameters |
1516 | 926 | ||
1517 | // Debugging routine for dumping detailed physical information for vehicle prims | ||
1518 | private void DumpVehicles() | ||
1519 | { | ||
1520 | foreach (BSPrim prim in m_vehicles) | ||
1521 | { | ||
1522 | BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); | ||
1523 | BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); | ||
1524 | } | ||
1525 | } | ||
1526 | |||
1527 | // Invoke the detailed logger and output something if it's enabled. | 927 | // Invoke the detailed logger and output something if it's enabled. |
1528 | public void DetailLog(string msg, params Object[] args) | 928 | public void DetailLog(string msg, params Object[] args) |
1529 | { | 929 | { |