aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
diff options
context:
space:
mode:
authorubit2012-08-02 18:21:08 +0200
committerubit2012-08-02 18:21:08 +0200
commit254d3e1ad31f99770074abb49fec03c90d99b246 (patch)
treefe2d2337f0fffec0f44a9f35442d73c8fe78fda3 /OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
parenti local libs commit (diff)
parentMerge branch 'master' into careminster (diff)
downloadopensim-SC-254d3e1ad31f99770074abb49fec03c90d99b246.zip
opensim-SC-254d3e1ad31f99770074abb49fec03c90d99b246.tar.gz
opensim-SC-254d3e1ad31f99770074abb49fec03c90d99b246.tar.bz2
opensim-SC-254d3e1ad31f99770074abb49fec03c90d99b246.tar.xz
merge crap gerge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork
Conflicts: bin/Regions/Regions.ini.example bin/lib32/BulletSim.dll bin/lib32/libBulletSim.so bin/lib64/BulletSim.dll bin/lib64/libBulletSim.so
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs828
1 files changed, 555 insertions, 273 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f..28d5cb5 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -29,12 +29,14 @@ using System.Collections.Generic;
29using System.Runtime.InteropServices; 29using System.Runtime.InteropServices;
30using System.Text; 30using System.Text;
31using System.Threading; 31using System.Threading;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Framework;
34using OpenSim.Region.CoreModules;
35using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
35using OpenSim.Region.Physics.Manager; 36using OpenSim.Region.Physics.Manager;
37using Nini.Config;
38using log4net;
36using OpenMetaverse; 39using OpenMetaverse;
37using OpenSim.Region.Framework;
38 40
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Debug linkset 42// Debug linkset
@@ -44,15 +46,17 @@ using OpenSim.Region.Framework;
44// Compute physics FPS reasonably 46// Compute physics FPS reasonably
45// Based on material, set density and friction 47// Based on material, set density and friction
46// More efficient memory usage when passing hull information from BSPrim to BulletSim 48// More efficient memory usage when passing hull information from BSPrim to BulletSim
49// Move all logic out of the C++ code and into the C# code for easier future modifications.
47// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 50// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
48// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 51// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
49// At the moment, physical and phantom causes object to drop through the terrain 52// At the moment, physical and phantom causes object to drop through the terrain
50// Physical phantom objects and related typing (collision options ) 53// Physical phantom objects and related typing (collision options )
54// Use collision masks for collision with terrain and phantom objects
51// Check out llVolumeDetect. Must do something for that. 55// Check out llVolumeDetect. Must do something for that.
52// Should prim.link() and prim.delink() membership checking happen at taint time? 56// Should prim.link() and prim.delink() membership checking happen at taint time?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root.
53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
54// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
55// Use collision masks for collision with terrain and phantom objects
56// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) 60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
57// Implement LockAngularMotion 61// Implement LockAngularMotion
58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@@ -60,9 +64,6 @@ using OpenSim.Region.Framework;
60// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 64// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
61// Add PID movement operations. What does ScenePresence.MoveToTarget do? 65// Add PID movement operations. What does ScenePresence.MoveToTarget do?
62// Check terrain size. 128 or 127? 66// Check terrain size. 128 or 127?
63// Multiple contact points on collision?
64// See code in ode::near... calls to collision_accounting_events()
65// (This might not be a problem. ODE collects all the collisions with one object in one tick.)
66// Raycast 67// Raycast
67// 68//
68namespace OpenSim.Region.Physics.BulletSPlugin 69namespace OpenSim.Region.Physics.BulletSPlugin
@@ -72,6 +73,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
72 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
73 private static readonly string LogHeader = "[BULLETS SCENE]"; 74 private static readonly string LogHeader = "[BULLETS SCENE]";
74 75
76 public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
77
75 public string BulletSimVersion = "?"; 78 public string BulletSimVersion = "?";
76 79
77 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
@@ -84,6 +87,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
84 private uint m_worldID; 87 private uint m_worldID;
85 public uint WorldID { get { return m_worldID; } } 88 public uint WorldID { get { return m_worldID; } }
86 89
90 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } }
92
87 private bool m_initialized = false; 93 private bool m_initialized = false;
88 94
89 private int m_detailedStatsStep = 0; 95 private int m_detailedStatsStep = 0;
@@ -100,11 +106,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
100 get { return m_sculptLOD; } 106 get { return m_sculptLOD; }
101 } 107 }
102 108
109 private BulletSim m_worldSim;
110 public BulletSim World
111 {
112 get { return m_worldSim; }
113 }
114 private BSConstraintCollection m_constraintCollection;
115 public BSConstraintCollection Constraints
116 {
117 get { return m_constraintCollection; }
118 }
119
103 private int m_maxSubSteps; 120 private int m_maxSubSteps;
104 private float m_fixedTimeStep; 121 private float m_fixedTimeStep;
105 private long m_simulationStep = 0; 122 private long m_simulationStep = 0;
106 public long SimulationStep { get { return m_simulationStep; } } 123 public long SimulationStep { get { return m_simulationStep; } }
107 124
125 public float LastSimulatedTimestep { get; private set; }
126
108 // A value of the time now so all the collision and update routines do not have to get their own 127 // A value of the time now so all the collision and update routines do not have to get their own
109 // Set to 'now' just before all the prims and actors are called for collisions and updates 128 // Set to 'now' just before all the prims and actors are called for collisions and updates
110 private int m_simulationNowTime; 129 private int m_simulationNowTime;
@@ -121,6 +140,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
121 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
122 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes 141 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
123 142
143 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional
145
124 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
125 public const uint GROUNDPLANE_ID = 1; 147 public const uint GROUNDPLANE_ID = 1;
126 148
@@ -147,8 +169,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
147 ConfigurationParameters[] m_params; 169 ConfigurationParameters[] m_params;
148 GCHandle m_paramsHandle; 170 GCHandle m_paramsHandle;
149 171
172 public bool shouldDebugLog { get; private set; }
173
150 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 174 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
151 175
176 // Sometimes you just have to log everything.
177 public Logging.LogWriter PhysicsLogging;
178 private bool m_physicsLoggingEnabled;
179 private string m_physicsLoggingDir;
180 private string m_physicsLoggingPrefix;
181 private int m_physicsLoggingFileMinutes;
182
183 private bool m_vehicleLoggingEnabled;
184 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
185
152 public BSScene(string identifier) 186 public BSScene(string identifier)
153 { 187 {
154 m_initialized = false; 188 m_initialized = false;
@@ -169,17 +203,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
169 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 203 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
170 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 204 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
171 205
206 // Enable very detailed logging.
207 // By creating an empty logger when not logging, the log message invocation code
208 // can be left in and every call doesn't have to check for null.
209 if (m_physicsLoggingEnabled)
210 {
211 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
212 }
213 else
214 {
215 PhysicsLogging = new Logging.LogWriter();
216 }
217
172 // Get the version of the DLL 218 // Get the version of the DLL
173 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 219 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
174 // BulletSimVersion = BulletSimAPI.GetVersion(); 220 // BulletSimVersion = BulletSimAPI.GetVersion();
175 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); 221 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
176 222
177 // if Debug, enable logging from the unmanaged code 223 // if Debug, enable logging from the unmanaged code
178 if (m_log.IsDebugEnabled) 224 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
179 { 225 {
180 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 226 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
181 // the handle is saved to it doesn't get freed after this call 227 if (PhysicsLogging.Enabled)
182 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 228 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
229 else
230 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
231 // the handle is saved in a variable to make sure it doesn't get freed after this call
183 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); 232 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
184 } 233 }
185 234
@@ -194,6 +243,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
194 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 243 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
195 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 244 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
196 245
246 // Initialization to support the transition to a new API which puts most of the logic
247 // into the C# code so it is easier to modify and add to.
248 m_worldSim = new BulletSim(m_worldID, BulletSimAPI.GetSimHandle2(m_worldID));
249 m_constraintCollection = new BSConstraintCollection(World);
250
197 m_initialized = true; 251 m_initialized = true;
198 } 252 }
199 253
@@ -202,110 +256,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
202 private void GetInitialParameterValues(IConfigSource config) 256 private void GetInitialParameterValues(IConfigSource config)
203 { 257 {
204 ConfigurationParameters parms = new ConfigurationParameters(); 258 ConfigurationParameters parms = new ConfigurationParameters();
259 m_params[0] = parms;
205 260
206 _meshSculptedPrim = true; // mesh sculpted prims 261 SetParameterDefaultValues();
207 _forceSimplePrimMeshing = false; // use complex meshing if called for
208
209 m_meshLOD = 8f;
210 m_sculptLOD = 32f;
211
212 m_detailedStatsStep = 0; // disabled
213
214 m_maxSubSteps = 10;
215 m_fixedTimeStep = 1f / 60f;
216 m_maxCollisionsPerFrame = 2048;
217 m_maxUpdatesPerFrame = 2048;
218 m_maximumObjectMass = 10000.01f;
219
220 parms.defaultFriction = 0.5f;
221 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
222 parms.defaultRestitution = 0f;
223 parms.collisionMargin = 0.0f;
224 parms.gravity = -9.80665f;
225
226 parms.linearDamping = 0.0f;
227 parms.angularDamping = 0.0f;
228 parms.deactivationTime = 0.2f;
229 parms.linearSleepingThreshold = 0.8f;
230 parms.angularSleepingThreshold = 1.0f;
231 parms.ccdMotionThreshold = 0.0f; // set to zero to disable
232 parms.ccdSweptSphereRadius = 0.0f;
233 parms.contactProcessingThreshold = 0.1f;
234
235 parms.terrainFriction = 0.5f;
236 parms.terrainHitFraction = 0.8f;
237 parms.terrainRestitution = 0f;
238 parms.avatarFriction = 0.5f;
239 parms.avatarRestitution = 0.0f;
240 parms.avatarDensity = 60f;
241 parms.avatarCapsuleRadius = 0.37f;
242 parms.avatarCapsuleHeight = 1.5f; // 2.140599f
243 parms.avatarContactProcessingThreshold = 0.1f;
244
245 parms.maxPersistantManifoldPoolSize = 0f;
246 parms.shouldDisableContactPoolDynamicAllocation = ConfigurationParameters.numericTrue;
247 parms.shouldForceUpdateAllAabbs = ConfigurationParameters.numericFalse;
248 parms.shouldRandomizeSolverOrder = ConfigurationParameters.numericFalse;
249 parms.shouldSplitSimulationIslands = ConfigurationParameters.numericFalse;
250 parms.shouldEnableFrictionCaching = ConfigurationParameters.numericFalse;
251 parms.numberOfSolverIterations = 0f; // means use default
252 262
253 if (config != null) 263 if (config != null)
254 { 264 {
255 // If there are specifications in the ini file, use those values 265 // If there are specifications in the ini file, use those values
256 // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini
257 // ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS.
258 IConfig pConfig = config.Configs["BulletSim"]; 266 IConfig pConfig = config.Configs["BulletSim"];
259 if (pConfig != null) 267 if (pConfig != null)
260 { 268 {
261 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); 269 SetParameterConfigurationValues(pConfig);
262 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); 270
263 271 // Very detailed logging for physics debugging
264 m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep); 272 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
265 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); 273 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
266 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); 274 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-");
267 275 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
268 m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps); 276 // Very detailed logging for vehicle debugging
269 m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep); 277 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
270 m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
271 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
272 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
273
274 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
275 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
276 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
277 parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
278 parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
279
280 parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
281 parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
282 parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
283 parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
284 parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
285 parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
286 parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
287 parms.contactProcessingThreshold = pConfig.GetFloat("ContactProcessingThreshold", parms.contactProcessingThreshold);
288
289 parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
290 parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
291 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
292 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
293 parms.avatarRestitution = pConfig.GetFloat("AvatarRestitution", parms.avatarRestitution);
294 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
295 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
296 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
297 parms.avatarContactProcessingThreshold = pConfig.GetFloat("AvatarContactProcessingThreshold", parms.avatarContactProcessingThreshold);
298
299 parms.maxPersistantManifoldPoolSize = pConfig.GetFloat("MaxPersistantManifoldPoolSize", parms.maxPersistantManifoldPoolSize);
300 parms.shouldDisableContactPoolDynamicAllocation = ParamBoolean(pConfig, "ShouldDisableContactPoolDynamicAllocation", parms.shouldDisableContactPoolDynamicAllocation);
301 parms.shouldForceUpdateAllAabbs = ParamBoolean(pConfig, "ShouldForceUpdateAllAabbs", parms.shouldForceUpdateAllAabbs);
302 parms.shouldRandomizeSolverOrder = ParamBoolean(pConfig, "ShouldRandomizeSolverOrder", parms.shouldRandomizeSolverOrder);
303 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
304 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
305 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
306 } 278 }
307 } 279 }
308 m_params[0] = parms;
309 } 280 }
310 281
311 // A helper function that handles a true/false parameter and returns the proper float number encoding 282 // A helper function that handles a true/false parameter and returns the proper float number encoding
@@ -323,12 +294,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
323 return ret; 294 return ret;
324 } 295 }
325 296
326
327 // Called directly from unmanaged code so don't do much 297 // Called directly from unmanaged code so don't do much
328 private void BulletLogger(string msg) 298 private void BulletLogger(string msg)
329 { 299 {
330 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 300 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
331 } 301 }
302
303 // Called directly from unmanaged code so don't do much
304 private void BulletLoggerPhysLog(string msg)
305 {
306 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
307 }
332 308
333 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 309 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
334 { 310 {
@@ -339,6 +315,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
339 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) 315 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
340 { 316 {
341 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); 317 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
318
319 if (!m_initialized) return null;
320
342 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 321 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
343 lock (m_avatars) m_avatars.Add(localID, actor); 322 lock (m_avatars) m_avatars.Add(localID, actor);
344 return actor; 323 return actor;
@@ -347,34 +326,47 @@ public class BSScene : PhysicsScene, IPhysicsParameters
347 public override void RemoveAvatar(PhysicsActor actor) 326 public override void RemoveAvatar(PhysicsActor actor)
348 { 327 {
349 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); 328 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
350 if (actor is BSCharacter) 329
351 { 330 if (!m_initialized) return;
352 ((BSCharacter)actor).Destroy(); 331
353 } 332 BSCharacter bsactor = actor as BSCharacter;
354 try 333 if (bsactor != null)
355 {
356 lock (m_avatars) m_avatars.Remove(actor.LocalID);
357 }
358 catch (Exception e)
359 { 334 {
360 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); 335 try
336 {
337 lock (m_avatars) m_avatars.Remove(actor.LocalID);
338 }
339 catch (Exception e)
340 {
341 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
342 }
343 bsactor.Destroy();
344 // bsactor.dispose();
361 } 345 }
362 } 346 }
363 347
364 public override void RemovePrim(PhysicsActor prim) 348 public override void RemovePrim(PhysicsActor prim)
365 { 349 {
366 // m_log.DebugFormat("{0}: RemovePrim", LogHeader); 350 if (!m_initialized) return;
367 if (prim is BSPrim) 351
368 { 352 BSPrim bsprim = prim as BSPrim;
369 ((BSPrim)prim).Destroy(); 353 if (bsprim != null)
370 }
371 try
372 { 354 {
373 lock (m_prims) m_prims.Remove(prim.LocalID); 355 m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
356 try
357 {
358 lock (m_prims) m_prims.Remove(bsprim.LocalID);
359 }
360 catch (Exception e)
361 {
362 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
363 }
364 bsprim.Destroy();
365 // bsprim.dispose();
374 } 366 }
375 catch (Exception e) 367 else
376 { 368 {
377 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); 369 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
378 } 370 }
379 } 371 }
380 372
@@ -382,6 +374,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
382 Vector3 size, Quaternion rotation, bool isPhysical, uint localID) 374 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
383 { 375 {
384 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); 376 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
377
378 if (!m_initialized) return null;
379
385 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 380 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
386 lock (m_prims) m_prims.Add(localID, prim); 381 lock (m_prims) m_prims.Add(localID, prim);
387 return prim; 382 return prim;
@@ -400,6 +395,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 int collidersCount; 395 int collidersCount;
401 IntPtr collidersPtr; 396 IntPtr collidersPtr;
402 397
398 LastSimulatedTimestep = timeStep;
399
403 // prevent simulation until we've been initialized 400 // prevent simulation until we've been initialized
404 if (!m_initialized) return 10.0f; 401 if (!m_initialized) return 10.0f;
405 402
@@ -459,7 +456,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
459 for (int ii = 0; ii < updatedEntityCount; ii++) 456 for (int ii = 0; ii < updatedEntityCount; ii++)
460 { 457 {
461 EntityProperties entprop = m_updateArray[ii]; 458 EntityProperties entprop = m_updateArray[ii];
462 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
463 BSPrim prim; 459 BSPrim prim;
464 if (m_prims.TryGetValue(entprop.ID, out prim)) 460 if (m_prims.TryGetValue(entprop.ID, out prim))
465 { 461 {
@@ -532,8 +528,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
532 }); 528 });
533 } 529 }
534 530
531 // Someday we will have complex terrain with caves and tunnels
532 // For the moment, it's flat and convex
533 public float GetTerrainHeightAtXYZ(Vector3 loc)
534 {
535 return GetTerrainHeightAtXY(loc.X, loc.Y);
536 }
537
535 public float GetTerrainHeightAtXY(float tX, float tY) 538 public float GetTerrainHeightAtXY(float tX, float tY)
536 { 539 {
540 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
541 return 30;
537 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; 542 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
538 } 543 }
539 544
@@ -555,6 +560,33 @@ public class BSScene : PhysicsScene, IPhysicsParameters
555 public override void Dispose() 560 public override void Dispose()
556 { 561 {
557 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 562 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
563
564 // make sure no stepping happens while we're deleting stuff
565 m_initialized = false;
566
567 if (m_constraintCollection != null)
568 {
569 m_constraintCollection.Dispose();
570 m_constraintCollection = null;
571 }
572
573 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
574 {
575 kvp.Value.Destroy();
576 }
577 m_avatars.Clear();
578
579 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
580 {
581 kvp.Value.Destroy();
582 }
583 m_prims.Clear();
584
585 // Anything left in the unmanaged code should be cleaned out
586 BulletSimAPI.Shutdown(WorldID);
587
588 // Not logging any more
589 PhysicsLogging.Close();
558 } 590 }
559 591
560 public override Dictionary<uint, float> GetTopColliders() 592 public override Dictionary<uint, float> GetTopColliders()
@@ -680,10 +712,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
680 } 712 }
681 713
682 // The calls to the PhysicsActors can't directly call into the physics engine 714 // The calls to the PhysicsActors can't directly call into the physics engine
683 // because it might be busy. We we delay changes to a known time. 715 // because it might be busy. We delay changes to a known time.
684 // We rely on C#'s closure to save and restore the context for the delegate. 716 // We rely on C#'s closure to save and restore the context for the delegate.
685 public void TaintedObject(TaintCallback callback) 717 public void TaintedObject(TaintCallback callback)
686 { 718 {
719 if (!m_initialized) return;
720
687 lock (_taintLock) 721 lock (_taintLock)
688 _taintedObjects.Add(callback); 722 _taintedObjects.Add(callback);
689 return; 723 return;
@@ -757,61 +791,392 @@ public class BSScene : PhysicsScene, IPhysicsParameters
757 } 791 }
758 #endregion Vehicles 792 #endregion Vehicles
759 793
760 #region Runtime settable parameters 794 #region Parameters
761 public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] 795
762 { 796 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
763 new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"), 797 delegate float ParamGet(BSScene scene);
764 new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), 798 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
765 new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), 799
766 new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), 800 private struct ParameterDefn
767 new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), 801 {
768 new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"), 802 public string name;
769 803 public string desc;
770 new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"), 804 public float defaultValue;
771 new PhysParameterEntry("DefaultDensity", "Density for new objects" ), 805 public ParamUser userParam;
772 new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ), 806 public ParamGet getter;
773 // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ), 807 public ParamSet setter;
774 new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ), 808 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
775 809 {
776 new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ), 810 name = n;
777 new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ), 811 desc = d;
778 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), 812 defaultValue = v;
779 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), 813 userParam = u;
780 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), 814 getter = g;
781 new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ), 815 setter = s;
782 new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ), 816 }
783 new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ), 817 }
784 // Can only change the following at initialization time. Change the INI file and reboot. 818
785 new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"), 819 // List of all of the externally visible parameters.
786 new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"), 820 // For each parameter, this table maps a text name to getter and setters.
787 new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"), 821 // To add a new externally referencable/settable parameter, add the paramter storage
788 new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"), 822 // location somewhere in the program and make an entry in this table with the
789 new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"), 823 // getters and setters.
790 new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"), 824 // To add a new variable, it is easiest to find an existing definition and copy it.
791 new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"), 825 // Parameter values are floats. Booleans are converted to a floating value.
792 826 //
793 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 827 // A ParameterDefn() takes the following parameters:
794 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 828 // -- the text name of the parameter. This is used for console input and ini file.
795 829 // -- a short text description of the parameter. This shows up in the console listing.
796 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 830 // -- a delegate for fetching the parameter from the ini file.
797 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 831 // Should handle fetching the right type from the ini file and converting it.
798 832 // -- a delegate for getting the value as a float
799 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), 833 // -- a delegate for setting the value from a float
800 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), 834 //
801 new PhysParameterEntry("TerrainRestitution", "Bouncyness" ), 835 // The single letter parameters for the delegates are:
802 new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ), 836 // s = BSScene
803 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), 837 // p = string parameter name
804 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), 838 // l = localID of referenced object
805 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), 839 // v = float value
806 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ), 840 // cf = parameter configuration class (for fetching values from ini file)
807 new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions") 841 private ParameterDefn[] ParameterDefinitions =
842 {
843 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
844 ConfigurationParameters.numericTrue,
845 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
846 (s) => { return s.NumericBool(s._meshSculptedPrim); },
847 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ),
848 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
849 ConfigurationParameters.numericFalse,
850 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
851 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); },
852 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ),
853
854 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
855 8f,
856 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
857 (s) => { return (float)s.m_meshLOD; },
858 (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
859 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
860 32,
861 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
862 (s) => { return (float)s.m_sculptLOD; },
863 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
864
865 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
866 10f,
867 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
868 (s) => { return (float)s.m_maxSubSteps; },
869 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
870 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
871 1f / 60f,
872 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
873 (s) => { return (float)s.m_fixedTimeStep; },
874 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
875 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
876 2048f,
877 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
878 (s) => { return (float)s.m_maxCollisionsPerFrame; },
879 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
880 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
881 8000f,
882 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
883 (s) => { return (float)s.m_maxUpdatesPerFrame; },
884 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
885 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
886 10000.01f,
887 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
888 (s) => { return (float)s.m_maximumObjectMass; },
889 (s,p,l,v) => { s.m_maximumObjectMass = v; } ),
890
891 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
892 2200f,
893 (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
894 (s) => { return (float)s.PID_D; },
895 (s,p,l,v) => { s.PID_D = v; } ),
896 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
897 900f,
898 (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
899 (s) => { return (float)s.PID_P; },
900 (s,p,l,v) => { s.PID_P = v; } ),
901
902 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
903 0.5f,
904 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
905 (s) => { return s.m_params[0].defaultFriction; },
906 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
907 new ParameterDefn("DefaultDensity", "Density for new objects" ,
908 10.000006836f, // Aluminum g/cm3
909 (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
910 (s) => { return s.m_params[0].defaultDensity; },
911 (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
912 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
913 0f,
914 (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
915 (s) => { return s.m_params[0].defaultRestitution; },
916 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
917 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
918 0f,
919 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
920 (s) => { return s.m_params[0].collisionMargin; },
921 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
922 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
923 -9.80665f,
924 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
925 (s) => { return s.m_params[0].gravity; },
926 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
927
928
929 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
930 0f,
931 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
932 (s) => { return s.m_params[0].linearDamping; },
933 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
934 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
935 0f,
936 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
937 (s) => { return s.m_params[0].angularDamping; },
938 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
939 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
940 0.2f,
941 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
942 (s) => { return s.m_params[0].deactivationTime; },
943 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
944 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
945 0.8f,
946 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
947 (s) => { return s.m_params[0].linearSleepingThreshold; },
948 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
949 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
950 1.0f,
951 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
952 (s) => { return s.m_params[0].angularSleepingThreshold; },
953 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
954 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
955 0f, // set to zero to disable
956 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
957 (s) => { return s.m_params[0].ccdMotionThreshold; },
958 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
959 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
960 0f,
961 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
962 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
963 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
964 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
965 0.1f,
966 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
967 (s) => { return s.m_params[0].contactProcessingThreshold; },
968 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
969
970 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
971 0.5f,
972 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
973 (s) => { return s.m_params[0].terrainFriction; },
974 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
975 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
976 0.8f,
977 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].terrainHitFraction; },
979 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
980 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
981 0f,
982 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].terrainRestitution; },
984 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
985 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
986 0.5f,
987 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].avatarFriction; },
989 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
990 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
991 60f,
992 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].avatarDensity; },
994 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
995 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
996 0f,
997 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].avatarRestitution; },
999 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1000 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1001 0.37f,
1002 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1004 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
1005 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1006 1.5f,
1007 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1009 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1010 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1011 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1015
1016
1017 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)",
1018 0f, // zero to disable
1019 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1020 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1021 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1022 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
1023 ConfigurationParameters.numericTrue,
1024 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1025 (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
1026 (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
1027 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
1028 ConfigurationParameters.numericFalse,
1029 (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1030 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1031 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1032 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1033 ConfigurationParameters.numericFalse,
1034 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1035 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1036 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1037 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1038 ConfigurationParameters.numericFalse,
1039 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1040 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1041 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
1042 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
1043 ConfigurationParameters.numericFalse,
1044 (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1045 (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
1046 (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
1047 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
1048 0f, // zero says use Bullet default
1049 (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
1050 (s) => { return s.m_params[0].numberOfSolverIterations; },
1051 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1052
1053 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1054 ConfigurationParameters.numericFalse,
1055 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1056 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1057 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
1058 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
1059 ConfigurationParameters.numericTrue,
1060 (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1061 (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
1062 (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
1063 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
1064 5.0f,
1065 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
1067 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
1068 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
1069 0.1f,
1070 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1072 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1073 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0",
1074 0.0f,
1075 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1076 (s) => { return s.m_params[0].linkConstraintCFM; },
1077 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1078 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1079 0.2f,
1080 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1081 (s) => { return s.m_params[0].linkConstraintERP; },
1082 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1083
1084 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1085 0f,
1086 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1087 (s) => { return (float)s.m_detailedStatsStep; },
1088 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
1089 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1090 ConfigurationParameters.numericFalse,
1091 (s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1092 (s) => { return s.NumericBool(s.shouldDebugLog); },
1093 (s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ),
808 1094
809 }; 1095 };
810 1096
1097 // Convert a boolean to our numeric true and false values
1098 public float NumericBool(bool b)
1099 {
1100 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
1101 }
1102
1103 // Convert numeric true and false values to a boolean
1104 public bool BoolNumeric(float b)
1105 {
1106 return (b == ConfigurationParameters.numericTrue ? true : false);
1107 }
1108
1109 // Search through the parameter definitions and return the matching
1110 // ParameterDefn structure.
1111 // Case does not matter as names are compared after converting to lower case.
1112 // Returns 'false' if the parameter is not found.
1113 private bool TryGetParameter(string paramName, out ParameterDefn defn)
1114 {
1115 bool ret = false;
1116 ParameterDefn foundDefn = new ParameterDefn();
1117 string pName = paramName.ToLower();
1118
1119 foreach (ParameterDefn parm in ParameterDefinitions)
1120 {
1121 if (pName == parm.name.ToLower())
1122 {
1123 foundDefn = parm;
1124 ret = true;
1125 break;
1126 }
1127 }
1128 defn = foundDefn;
1129 return ret;
1130 }
1131
1132 // Pass through the settable parameters and set the default values
1133 private void SetParameterDefaultValues()
1134 {
1135 foreach (ParameterDefn parm in ParameterDefinitions)
1136 {
1137 parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
1138 }
1139 }
1140
1141 // Get user set values out of the ini file.
1142 private void SetParameterConfigurationValues(IConfig cfg)
1143 {
1144 foreach (ParameterDefn parm in ParameterDefinitions)
1145 {
1146 parm.userParam(this, cfg, parm.name, parm.defaultValue);
1147 }
1148 }
1149
1150 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1151
1152 private void BuildParameterTable()
1153 {
1154 if (SettableParameters.Length < ParameterDefinitions.Length)
1155 {
1156
1157 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1158 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1159 {
1160 ParameterDefn pd = ParameterDefinitions[ii];
1161 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
1162 }
1163
1164 // make the list in alphabetical order for estetic reasons
1165 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
1166 {
1167 return ppe1.name.CompareTo(ppe2.name);
1168 });
1169
1170 SettableParameters = entries.ToArray();
1171 }
1172 }
1173
1174
811 #region IPhysicsParameters 1175 #region IPhysicsParameters
812 // Get the list of parameters this physics engine supports 1176 // Get the list of parameters this physics engine supports
813 public PhysParameterEntry[] GetParameterList() 1177 public PhysParameterEntry[] GetParameterList()
814 { 1178 {
1179 BuildParameterTable();
815 return SettableParameters; 1180 return SettableParameters;
816 } 1181 }
817 1182
@@ -823,63 +1188,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
823 // value activated ('terrainFriction' for instance). 1188 // value activated ('terrainFriction' for instance).
824 public bool SetPhysicsParameter(string parm, float val, uint localID) 1189 public bool SetPhysicsParameter(string parm, float val, uint localID)
825 { 1190 {
826 bool ret = true; 1191 bool ret = false;
827 string lparm = parm.ToLower(); 1192 ParameterDefn theParam;
828 switch (lparm) 1193 if (TryGetParameter(parm, out theParam))
829 { 1194 {
830 case "detailedstats": m_detailedStatsStep = (int)val; break; 1195 theParam.setter(this, parm, localID, val);
831 1196 ret = true;
832 case "meshlod": m_meshLOD = (int)val; break;
833 case "sculptlod": m_sculptLOD = (int)val; break;
834 case "maxsubstep": m_maxSubSteps = (int)val; break;
835 case "fixedtimestep": m_fixedTimeStep = val; break;
836 case "maxobjectmass": m_maximumObjectMass = val; break;
837
838 case "defaultfriction": m_params[0].defaultFriction = val; break;
839 case "defaultdensity": m_params[0].defaultDensity = val; break;
840 case "defaultrestitution": m_params[0].defaultRestitution = val; break;
841 case "collisionmargin": m_params[0].collisionMargin = val; break;
842 case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, localID, val); break;
843
844 case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
845 case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
846 case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break;
847 case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break;
848 case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
849 case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
850 case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
851 case "contactprocessingthreshold": UpdateParameterPrims(ref m_params[0].contactProcessingThreshold, lparm, localID, val); break;
852 // the following are used only at initialization time so setting them makes no sense
853 // case "maxPersistantmanifoldpoolSize": m_params[0].maxPersistantManifoldPoolSize = val; break;
854 // case "shoulddisablecontactpooldynamicallocation": m_params[0].shouldDisableContactPoolDynamicAllocation = val; break;
855 // case "shouldforceupdateallaabbs": m_params[0].shouldForceUpdateAllAabbs = val; break;
856 // case "shouldrandomizesolverorder": m_params[0].shouldRandomizeSolverOrder = val; break;
857 // case "shouldsplitsimulationislands": m_params[0].shouldSplitSimulationIslands = val; break;
858 // case "shouldenablefrictioncaching": m_params[0].shouldEnableFrictionCaching = val; break;
859 // case "numberofsolveriterations": m_params[0].numberOfSolverIterations = val; break;
860
861 case "friction": TaintedUpdateParameter(lparm, localID, val); break;
862 case "restitution": TaintedUpdateParameter(lparm, localID, val); break;
863
864 // set a terrain physical feature and cause terrain to be recalculated
865 case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
866 case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break;
867 case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break;
868 // set an avatar physical feature and cause avatar(s) to be recalculated
869 case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break;
870 case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break;
871 case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
872 case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
873 case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
874 case "avatarcontactprocessingthreshold": UpdateParameterAvatars(ref m_params[0].avatarContactProcessingThreshold, "avatar", localID, val); break;
875
876 default: ret = false; break;
877 } 1197 }
878 return ret; 1198 return ret;
879 } 1199 }
880 1200
881 // check to see if we are updating a parameter for a particular or all of the prims 1201 // check to see if we are updating a parameter for a particular or all of the prims
882 private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) 1202 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
883 { 1203 {
884 List<uint> operateOn; 1204 List<uint> operateOn;
885 lock (m_prims) operateOn = new List<uint>(m_prims.Keys); 1205 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
@@ -887,7 +1207,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
887 } 1207 }
888 1208
889 // check to see if we are updating a parameter for a particular or all of the avatars 1209 // check to see if we are updating a parameter for a particular or all of the avatars
890 private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val) 1210 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
891 { 1211 {
892 List<uint> operateOn; 1212 List<uint> operateOn;
893 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1213 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
@@ -898,7 +1218,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
898 // If the local ID is APPLY_TO_NONE, just change the default value 1218 // If the local ID is APPLY_TO_NONE, just change the default value
899 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1219 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
900 // If the localID is a specific object, apply the parameter change to only that object 1220 // If the localID is a specific object, apply the parameter change to only that object
901 private void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) 1221 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
902 { 1222 {
903 switch (localID) 1223 switch (localID)
904 { 1224 {
@@ -925,7 +1245,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
925 } 1245 }
926 1246
927 // schedule the actual updating of the paramter to when the phys engine is not busy 1247 // schedule the actual updating of the paramter to when the phys engine is not busy
928 private void TaintedUpdateParameter(string parm, uint localID, float val) 1248 protected void TaintedUpdateParameter(string parm, uint localID, float val)
929 { 1249 {
930 uint xlocalID = localID; 1250 uint xlocalID = localID;
931 string xparm = parm.ToLower(); 1251 string xparm = parm.ToLower();
@@ -940,50 +1260,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
940 public bool GetPhysicsParameter(string parm, out float value) 1260 public bool GetPhysicsParameter(string parm, out float value)
941 { 1261 {
942 float val = 0f; 1262 float val = 0f;
943 bool ret = true; 1263 bool ret = false;
944 switch (parm.ToLower()) 1264 ParameterDefn theParam;
945 { 1265 if (TryGetParameter(parm, out theParam))
946 case "detailedstats": val = (int)m_detailedStatsStep; break; 1266 {
947 case "meshlod": val = (float)m_meshLOD; break; 1267 val = theParam.getter(this);
948 case "sculptlod": val = (float)m_sculptLOD; break; 1268 ret = true;
949 case "maxsubstep": val = (float)m_maxSubSteps; break;
950 case "fixedtimestep": val = m_fixedTimeStep; break;
951 case "maxobjectmass": val = m_maximumObjectMass; break;
952
953 case "defaultfriction": val = m_params[0].defaultFriction; break;
954 case "defaultdensity": val = m_params[0].defaultDensity; break;
955 case "defaultrestitution": val = m_params[0].defaultRestitution; break;
956 case "collisionmargin": val = m_params[0].collisionMargin; break;
957 case "gravity": val = m_params[0].gravity; break;
958
959 case "lineardamping": val = m_params[0].linearDamping; break;
960 case "angulardamping": val = m_params[0].angularDamping; break;
961 case "deactivationtime": val = m_params[0].deactivationTime; break;
962 case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break;
963 case "angularsleepingthreshold": val = m_params[0].angularDamping; break;
964 case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
965 case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
966 case "contactprocessingthreshold": val = m_params[0].contactProcessingThreshold; break;
967 case "maxPersistantmanifoldpoolSize": val = m_params[0].maxPersistantManifoldPoolSize; break;
968 case "shoulddisablecontactpooldynamicallocation": val = m_params[0].shouldDisableContactPoolDynamicAllocation; break;
969 case "shouldforceupdateallaabbs": val = m_params[0].shouldForceUpdateAllAabbs; break;
970 case "shouldrandomizesolverorder": val = m_params[0].shouldRandomizeSolverOrder; break;
971 case "shouldsplitsimulationislands": val = m_params[0].shouldSplitSimulationIslands; break;
972 case "shouldenablefrictioncaching": val = m_params[0].shouldEnableFrictionCaching; break;
973 case "numberofsolveriterations": val = m_params[0].numberOfSolverIterations; break;
974
975 case "terrainfriction": val = m_params[0].terrainFriction; break;
976 case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
977 case "terrainrestitution": val = m_params[0].terrainRestitution; break;
978
979 case "avatarfriction": val = m_params[0].avatarFriction; break;
980 case "avatardensity": val = m_params[0].avatarDensity; break;
981 case "avatarrestitution": val = m_params[0].avatarRestitution; break;
982 case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
983 case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
984 case "avatarcontactprocessingthreshold": val = m_params[0].avatarContactProcessingThreshold; break;
985 default: ret = false; break;
986
987 } 1269 }
988 value = val; 1270 value = val;
989 return ret; 1271 return ret;