aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs796
1 files changed, 523 insertions, 273 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f..c6d622b 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 {
@@ -347,34 +323,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
347 public override void RemoveAvatar(PhysicsActor actor) 323 public override void RemoveAvatar(PhysicsActor actor)
348 { 324 {
349 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); 325 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
350 if (actor is BSCharacter) 326 BSCharacter bsactor = actor as BSCharacter;
351 { 327 if (bsactor != null)
352 ((BSCharacter)actor).Destroy();
353 }
354 try
355 { 328 {
356 lock (m_avatars) m_avatars.Remove(actor.LocalID); 329 try
357 } 330 {
358 catch (Exception e) 331 lock (m_avatars) m_avatars.Remove(actor.LocalID);
359 { 332 }
360 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); 333 catch (Exception e)
334 {
335 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
336 }
337 bsactor.Destroy();
338 // bsactor.dispose();
361 } 339 }
362 } 340 }
363 341
364 public override void RemovePrim(PhysicsActor prim) 342 public override void RemovePrim(PhysicsActor prim)
365 { 343 {
366 // m_log.DebugFormat("{0}: RemovePrim", LogHeader); 344 BSPrim bsprim = prim as BSPrim;
367 if (prim is BSPrim) 345 if (bsprim != null)
368 { 346 {
369 ((BSPrim)prim).Destroy(); 347 m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
370 } 348 try
371 try 349 {
372 { 350 lock (m_prims) m_prims.Remove(bsprim.LocalID);
373 lock (m_prims) m_prims.Remove(prim.LocalID); 351 }
352 catch (Exception e)
353 {
354 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
355 }
356 bsprim.Destroy();
357 // bsprim.dispose();
374 } 358 }
375 catch (Exception e) 359 else
376 { 360 {
377 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); 361 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
378 } 362 }
379 } 363 }
380 364
@@ -400,6 +384,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 int collidersCount; 384 int collidersCount;
401 IntPtr collidersPtr; 385 IntPtr collidersPtr;
402 386
387 LastSimulatedTimestep = timeStep;
388
403 // prevent simulation until we've been initialized 389 // prevent simulation until we've been initialized
404 if (!m_initialized) return 10.0f; 390 if (!m_initialized) return 10.0f;
405 391
@@ -459,7 +445,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
459 for (int ii = 0; ii < updatedEntityCount; ii++) 445 for (int ii = 0; ii < updatedEntityCount; ii++)
460 { 446 {
461 EntityProperties entprop = m_updateArray[ii]; 447 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; 448 BSPrim prim;
464 if (m_prims.TryGetValue(entprop.ID, out prim)) 449 if (m_prims.TryGetValue(entprop.ID, out prim))
465 { 450 {
@@ -532,8 +517,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
532 }); 517 });
533 } 518 }
534 519
520 // Someday we will have complex terrain with caves and tunnels
521 // For the moment, it's flat and convex
522 public float GetTerrainHeightAtXYZ(Vector3 loc)
523 {
524 return GetTerrainHeightAtXY(loc.X, loc.Y);
525 }
526
535 public float GetTerrainHeightAtXY(float tX, float tY) 527 public float GetTerrainHeightAtXY(float tX, float tY)
536 { 528 {
529 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
530 return 30;
537 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; 531 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
538 } 532 }
539 533
@@ -555,6 +549,33 @@ public class BSScene : PhysicsScene, IPhysicsParameters
555 public override void Dispose() 549 public override void Dispose()
556 { 550 {
557 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 551 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
552
553 // make sure no stepping happens while we're deleting stuff
554 m_initialized = false;
555
556 if (m_constraintCollection != null)
557 {
558 m_constraintCollection.Dispose();
559 m_constraintCollection = null;
560 }
561
562 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
563 {
564 kvp.Value.Destroy();
565 }
566 m_avatars.Clear();
567
568 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
569 {
570 kvp.Value.Destroy();
571 }
572 m_prims.Clear();
573
574 // Anything left in the unmanaged code should be cleaned out
575 BulletSimAPI.Shutdown(WorldID);
576
577 // Not logging any more
578 PhysicsLogging.Close();
558 } 579 }
559 580
560 public override Dictionary<uint, float> GetTopColliders() 581 public override Dictionary<uint, float> GetTopColliders()
@@ -680,10 +701,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
680 } 701 }
681 702
682 // The calls to the PhysicsActors can't directly call into the physics engine 703 // 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. 704 // 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. 705 // We rely on C#'s closure to save and restore the context for the delegate.
685 public void TaintedObject(TaintCallback callback) 706 public void TaintedObject(TaintCallback callback)
686 { 707 {
708 if (!m_initialized) return;
709
687 lock (_taintLock) 710 lock (_taintLock)
688 _taintedObjects.Add(callback); 711 _taintedObjects.Add(callback);
689 return; 712 return;
@@ -757,61 +780,371 @@ public class BSScene : PhysicsScene, IPhysicsParameters
757 } 780 }
758 #endregion Vehicles 781 #endregion Vehicles
759 782
760 #region Runtime settable parameters 783 #region Parameters
761 public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] 784
762 { 785 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)"), 786 delegate float ParamGet(BSScene scene);
764 new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), 787 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
765 new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), 788
766 new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), 789 private struct ParameterDefn
767 new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), 790 {
768 new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"), 791 public string name;
769 792 public string desc;
770 new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"), 793 public float defaultValue;
771 new PhysParameterEntry("DefaultDensity", "Density for new objects" ), 794 public ParamUser userParam;
772 new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ), 795 public ParamGet getter;
773 // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ), 796 public ParamSet setter;
774 new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ), 797 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
775 798 {
776 new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ), 799 name = n;
777 new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ), 800 desc = d;
778 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), 801 defaultValue = v;
779 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), 802 userParam = u;
780 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), 803 getter = g;
781 new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ), 804 setter = s;
782 new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ), 805 }
783 new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ), 806 }
784 // Can only change the following at initialization time. Change the INI file and reboot. 807
785 new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"), 808 // List of all of the externally visible parameters.
786 new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"), 809 // For each parameter, this table maps a text name to getter and setters.
787 new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"), 810 // A ParameterDefn() takes the following parameters:
788 new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"), 811 // -- the text name of the parameter. This is used for console input and ini file.
789 new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"), 812 // -- a short text description of the parameter. This shows up in the console listing.
790 new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"), 813 // -- a delegate for fetching the parameter from the ini file.
791 new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"), 814 // Should handle fetching the right type from the ini file and converting it.
792 815 // -- a delegate for getting the value as a float
793 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 816 // -- a delegate for setting the value from a float
794 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 817 //
795 818 // To add a new variable, it is best to find an existing definition and copy it.
796 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), 819 private ParameterDefn[] ParameterDefinitions =
797 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 820 {
798 821 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
799 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), 822 ConfigurationParameters.numericTrue,
800 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), 823 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
801 new PhysParameterEntry("TerrainRestitution", "Bouncyness" ), 824 (s) => { return s.NumericBool(s._meshSculptedPrim); },
802 new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ), 825 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ),
803 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), 826 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
804 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), 827 ConfigurationParameters.numericFalse,
805 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), 828 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
806 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ), 829 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); },
807 new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions") 830 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ),
831
832 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
833 8f,
834 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
835 (s) => { return (float)s.m_meshLOD; },
836 (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
837 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
838 32,
839 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
840 (s) => { return (float)s.m_sculptLOD; },
841 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
842
843 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
844 10f,
845 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
846 (s) => { return (float)s.m_maxSubSteps; },
847 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
848 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
849 1f / 60f,
850 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
851 (s) => { return (float)s.m_fixedTimeStep; },
852 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
853 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
854 2048f,
855 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
856 (s) => { return (float)s.m_maxCollisionsPerFrame; },
857 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
858 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
859 8000f,
860 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
861 (s) => { return (float)s.m_maxUpdatesPerFrame; },
862 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
863 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
864 10000.01f,
865 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
866 (s) => { return (float)s.m_maximumObjectMass; },
867 (s,p,l,v) => { s.m_maximumObjectMass = v; } ),
868
869 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
870 2200f,
871 (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
872 (s) => { return (float)s.PID_D; },
873 (s,p,l,v) => { s.PID_D = v; } ),
874 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
875 900f,
876 (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
877 (s) => { return (float)s.PID_P; },
878 (s,p,l,v) => { s.PID_P = v; } ),
879
880 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
881 0.5f,
882 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
883 (s) => { return s.m_params[0].defaultFriction; },
884 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
885 new ParameterDefn("DefaultDensity", "Density for new objects" ,
886 10.000006836f, // Aluminum g/cm3
887 (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
888 (s) => { return s.m_params[0].defaultDensity; },
889 (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
890 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
891 0f,
892 (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
893 (s) => { return s.m_params[0].defaultRestitution; },
894 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
895 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
896 0f,
897 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
898 (s) => { return s.m_params[0].collisionMargin; },
899 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
900 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
901 -9.80665f,
902 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
903 (s) => { return s.m_params[0].gravity; },
904 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
905
906
907 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
908 0f,
909 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
910 (s) => { return s.m_params[0].linearDamping; },
911 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
912 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
913 0f,
914 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
915 (s) => { return s.m_params[0].angularDamping; },
916 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
917 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
918 0.2f,
919 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
920 (s) => { return s.m_params[0].deactivationTime; },
921 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
922 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
923 0.8f,
924 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
925 (s) => { return s.m_params[0].linearSleepingThreshold; },
926 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
927 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
928 1.0f,
929 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
930 (s) => { return s.m_params[0].angularSleepingThreshold; },
931 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
932 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
933 0f, // set to zero to disable
934 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
935 (s) => { return s.m_params[0].ccdMotionThreshold; },
936 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
937 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
938 0f,
939 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
940 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
941 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
942 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
943 0.1f,
944 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
945 (s) => { return s.m_params[0].contactProcessingThreshold; },
946 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
947
948 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
949 0.5f,
950 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
951 (s) => { return s.m_params[0].terrainFriction; },
952 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
953 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
954 0.8f,
955 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
956 (s) => { return s.m_params[0].terrainHitFraction; },
957 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
958 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
959 0f,
960 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
961 (s) => { return s.m_params[0].terrainRestitution; },
962 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
963 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
964 0.5f,
965 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
966 (s) => { return s.m_params[0].avatarFriction; },
967 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
968 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
969 60f,
970 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].avatarDensity; },
972 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
973 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
974 0f,
975 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
976 (s) => { return s.m_params[0].avatarRestitution; },
977 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
978 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
979 0.37f,
980 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
981 (s) => { return s.m_params[0].avatarCapsuleRadius; },
982 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
983 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
984 1.5f,
985 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
986 (s) => { return s.m_params[0].avatarCapsuleHeight; },
987 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
988 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
989 0.1f,
990 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
991 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
992 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
993
994
995 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)",
996 0f, // zero to disable
997 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
999 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1000 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
1001 ConfigurationParameters.numericTrue,
1002 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1003 (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
1004 (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
1005 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
1006 ConfigurationParameters.numericFalse,
1007 (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1008 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1009 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1010 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1011 ConfigurationParameters.numericFalse,
1012 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1013 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1014 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1015 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1016 ConfigurationParameters.numericFalse,
1017 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1018 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1019 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
1020 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
1021 ConfigurationParameters.numericFalse,
1022 (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1023 (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
1024 (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
1025 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
1026 0f, // zero says use Bullet default
1027 (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
1028 (s) => { return s.m_params[0].numberOfSolverIterations; },
1029 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1030
1031 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1032 ConfigurationParameters.numericFalse,
1033 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1034 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1035 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
1036 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
1037 ConfigurationParameters.numericTrue,
1038 (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1039 (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
1040 (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
1041 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
1042 5.0f,
1043 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
1045 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
1046 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
1047 0.1f,
1048 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1050 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1051
1052 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1053 0f,
1054 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1055 (s) => { return (float)s.m_detailedStatsStep; },
1056 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
1057 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1058 ConfigurationParameters.numericFalse,
1059 (s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1060 (s) => { return s.NumericBool(s.shouldDebugLog); },
1061 (s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ),
808 1062
809 }; 1063 };
810 1064
1065 // Convert a boolean to our numeric true and false values
1066 public float NumericBool(bool b)
1067 {
1068 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
1069 }
1070
1071 // Convert numeric true and false values to a boolean
1072 public bool BoolNumeric(float b)
1073 {
1074 return (b == ConfigurationParameters.numericTrue ? true : false);
1075 }
1076
1077 // Search through the parameter definitions and return the matching
1078 // ParameterDefn structure.
1079 // Case does not matter as names are compared after converting to lower case.
1080 // Returns 'false' if the parameter is not found.
1081 private bool TryGetParameter(string paramName, out ParameterDefn defn)
1082 {
1083 bool ret = false;
1084 ParameterDefn foundDefn = new ParameterDefn();
1085 string pName = paramName.ToLower();
1086
1087 foreach (ParameterDefn parm in ParameterDefinitions)
1088 {
1089 if (pName == parm.name.ToLower())
1090 {
1091 foundDefn = parm;
1092 ret = true;
1093 break;
1094 }
1095 }
1096 defn = foundDefn;
1097 return ret;
1098 }
1099
1100 // Pass through the settable parameters and set the default values
1101 private void SetParameterDefaultValues()
1102 {
1103 foreach (ParameterDefn parm in ParameterDefinitions)
1104 {
1105 parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
1106 }
1107 }
1108
1109 // Get user set values out of the ini file.
1110 private void SetParameterConfigurationValues(IConfig cfg)
1111 {
1112 foreach (ParameterDefn parm in ParameterDefinitions)
1113 {
1114 parm.userParam(this, cfg, parm.name, parm.defaultValue);
1115 }
1116 }
1117
1118 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1119
1120 private void BuildParameterTable()
1121 {
1122 if (SettableParameters.Length < ParameterDefinitions.Length)
1123 {
1124
1125 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1126 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1127 {
1128 ParameterDefn pd = ParameterDefinitions[ii];
1129 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
1130 }
1131
1132 // make the list in alphabetical order for estetic reasons
1133 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
1134 {
1135 return ppe1.name.CompareTo(ppe2.name);
1136 });
1137
1138 SettableParameters = entries.ToArray();
1139 }
1140 }
1141
1142
811 #region IPhysicsParameters 1143 #region IPhysicsParameters
812 // Get the list of parameters this physics engine supports 1144 // Get the list of parameters this physics engine supports
813 public PhysParameterEntry[] GetParameterList() 1145 public PhysParameterEntry[] GetParameterList()
814 { 1146 {
1147 BuildParameterTable();
815 return SettableParameters; 1148 return SettableParameters;
816 } 1149 }
817 1150
@@ -823,63 +1156,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
823 // value activated ('terrainFriction' for instance). 1156 // value activated ('terrainFriction' for instance).
824 public bool SetPhysicsParameter(string parm, float val, uint localID) 1157 public bool SetPhysicsParameter(string parm, float val, uint localID)
825 { 1158 {
826 bool ret = true; 1159 bool ret = false;
827 string lparm = parm.ToLower(); 1160 ParameterDefn theParam;
828 switch (lparm) 1161 if (TryGetParameter(parm, out theParam))
829 { 1162 {
830 case "detailedstats": m_detailedStatsStep = (int)val; break; 1163 theParam.setter(this, parm, localID, val);
831 1164 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 } 1165 }
878 return ret; 1166 return ret;
879 } 1167 }
880 1168
881 // check to see if we are updating a parameter for a particular or all of the prims 1169 // 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) 1170 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
883 { 1171 {
884 List<uint> operateOn; 1172 List<uint> operateOn;
885 lock (m_prims) operateOn = new List<uint>(m_prims.Keys); 1173 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
@@ -887,7 +1175,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
887 } 1175 }
888 1176
889 // check to see if we are updating a parameter for a particular or all of the avatars 1177 // 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) 1178 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
891 { 1179 {
892 List<uint> operateOn; 1180 List<uint> operateOn;
893 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1181 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
@@ -898,7 +1186,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
898 // If the local ID is APPLY_TO_NONE, just change the default value 1186 // 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 1187 // 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 1188 // 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) 1189 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
902 { 1190 {
903 switch (localID) 1191 switch (localID)
904 { 1192 {
@@ -925,7 +1213,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
925 } 1213 }
926 1214
927 // schedule the actual updating of the paramter to when the phys engine is not busy 1215 // 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) 1216 protected void TaintedUpdateParameter(string parm, uint localID, float val)
929 { 1217 {
930 uint xlocalID = localID; 1218 uint xlocalID = localID;
931 string xparm = parm.ToLower(); 1219 string xparm = parm.ToLower();
@@ -940,50 +1228,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
940 public bool GetPhysicsParameter(string parm, out float value) 1228 public bool GetPhysicsParameter(string parm, out float value)
941 { 1229 {
942 float val = 0f; 1230 float val = 0f;
943 bool ret = true; 1231 bool ret = false;
944 switch (parm.ToLower()) 1232 ParameterDefn theParam;
945 { 1233 if (TryGetParameter(parm, out theParam))
946 case "detailedstats": val = (int)m_detailedStatsStep; break; 1234 {
947 case "meshlod": val = (float)m_meshLOD; break; 1235 val = theParam.getter(this);
948 case "sculptlod": val = (float)m_sculptLOD; break; 1236 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 } 1237 }
988 value = val; 1238 value = val;
989 return ret; 1239 return ret;