aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs621
1 files changed, 263 insertions, 358 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..52997dd 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,8 +39,6 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Debug linkset
43// Test with multiple regions in one simulator
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) 42// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties 43// Test sculpties
46// Compute physics FPS reasonably 44// Compute physics FPS reasonably
@@ -54,13 +52,10 @@ using OpenMetaverse;
54// Use collision masks for collision with terrain and phantom objects 52// Use collision masks for collision with terrain and phantom objects
55// Check out llVolumeDetect. Must do something for that. 53// Check out llVolumeDetect. Must do something for that.
56// Should prim.link() and prim.delink() membership checking happen at taint time? 54// 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.
58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 55// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 56// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
61// Implement LockAngularMotion 57// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
63// Does NeedsMeshing() really need to exclude all the different shapes?
64// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 59// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
65// Add PID movement operations. What does ScenePresence.MoveToTarget do? 60// Add PID movement operations. What does ScenePresence.MoveToTarget do?
66// Check terrain size. 128 or 127? 61// Check terrain size. 128 or 127?
@@ -73,62 +68,56 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 68 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 69 private static readonly string LogHeader = "[BULLETS SCENE]";
75 70
76 public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } 71 // The name of the region we're working for.
72 public string RegionName { get; private set; }
77 73
78 public string BulletSimVersion = "?"; 74 public string BulletSimVersion = "?";
79 75
80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 76 public Dictionary<uint, BSPhysObject> PhysObjects = new Dictionary<uint, BSPhysObject>();
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 77
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); 78 private HashSet<BSPhysObject> m_objectsWithCollisions = new HashSet<BSPhysObject>();
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>(); 79 // Following is a kludge and can be removed when avatar animation updating is
84 private List<BSPrim> m_vehicles = new List<BSPrim>(); 80 // moved to a better place.
85 private float[] m_heightMap; 81 private HashSet<BSPhysObject> m_avatarsWithCollisions = new HashSet<BSPhysObject>();
86 private float m_waterLevel; 82
87 private uint m_worldID; 83 // List of all the objects that have vehicle properties and should be called
88 public uint WorldID { get { return m_worldID; } } 84 // to update each physics step.
85 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
89 86
90 // let my minuions use my logger 87 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } } 88 public ILog Logger { get { return m_log; } }
92 89
93 private bool m_initialized = false; 90 // If non-zero, the number of simulation steps between calls to the physics
94 91 // engine to output detailed physics stats. Debug logging level must be on also.
95 private int m_detailedStatsStep = 0; 92 private int m_detailedStatsStep = 0;
96 93
97 public IMesher mesher; 94 public IMesher mesher;
98 private float m_meshLOD; 95 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 96 public float MeshLOD { get; private set; }
100 { 97 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 98 public float MeshMegaPrimThreshold { get; private set; }
102 } 99 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 100
109 private BulletSim m_worldSim; 101 public uint WorldID { get; private set; }
110 public BulletSim World 102 public BulletSim World { get; private set; }
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
104 // All the constraints that have been allocated in this instance.
105 public BSConstraintCollection Constraints { get; private set; }
106
107 // Simulation parameters
120 private int m_maxSubSteps; 108 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 109 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 110 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 111 public long SimulationStep { get { return m_simulationStep; } }
124 112
125 public float LastSimulatedTimestep { get; private set; }
126
127 // A value of the time now so all the collision and update routines do not have to get their own 113 // A value of the time now so all the collision and update routines do not have to get their own
128 // Set to 'now' just before all the prims and actors are called for collisions and updates 114 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 115 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 116
117 // True if initialized and ready to do simulation steps
118 private bool m_initialized = false;
131 119
120 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 121 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 122 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 123 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +126,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 126 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 127 private GCHandle m_updateArrayPinnedHandle;
139 128
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 129 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
141 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes 130 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
142 131
143 public float PID_D { get; private set; } // derivative 132 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional 133 public float PID_P { get; private set; } // proportional
145 134
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 135 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 136 public const uint GROUNDPLANE_ID = 1;
137 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
138
139 private float m_waterLevel;
140 public BSTerrainManager TerrainManager { get; private set; }
148 141
149 public ConfigurationParameters Params 142 public ConfigurationParameters Params
150 { 143 {
@@ -154,13 +147,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
154 { 147 {
155 get { return new Vector3(0f, 0f, Params.gravity); } 148 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 149 }
157 150 // Just the Z value of the gravity
158 private float m_maximumObjectMass; 151 public float DefaultGravityZ
159 public float MaximumObjectMass
160 { 152 {
161 get { return m_maximumObjectMass; } 153 get { return Params.gravity; }
162 } 154 }
163 155
156 public float MaximumObjectMass { get; private set; }
157
158 // When functions in the unmanaged code must be called, it is only
159 // done at a known time just before the simulation step. The taint
160 // system saves all these function calls and executes them in
161 // order before the simulation.
164 public delegate void TaintCallback(); 162 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 163 private struct TaintCallbackEntry
166 { 164 {
@@ -172,15 +170,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 callback = c; 170 callback = c;
173 } 171 }
174 } 172 }
173 private Object _taintLock = new Object(); // lock for using the next object
175 private List<TaintCallbackEntry> _taintedObjects; 174 private List<TaintCallbackEntry> _taintedObjects;
176 private Object _taintLock = new Object();
177 175
178 // A pointer to an instance if this structure is passed to the C++ code 176 // A pointer to an instance if this structure is passed to the C++ code
177 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 178 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 179 GCHandle m_paramsHandle;
181 180
182 public bool ShouldDebugLog { get; private set; } 181 // Handle to the callback used by the unmanaged code to call into the managed code.
183 182 // Used for debug logging.
183 // Need to store the handle in a persistant variable so it won't be freed.
184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
185 185
186 // Sometimes you just have to log everything. 186 // Sometimes you just have to log everything.
@@ -189,13 +189,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private string m_physicsLoggingDir; 189 private string m_physicsLoggingDir;
190 private string m_physicsLoggingPrefix; 190 private string m_physicsLoggingPrefix;
191 private int m_physicsLoggingFileMinutes; 191 private int m_physicsLoggingFileMinutes;
192 // 'true' of the vehicle code is to log lots of details
193 public bool VehicleLoggingEnabled { get; private set; }
192 194
193 private bool m_vehicleLoggingEnabled; 195 #region Construction and Initialization
194 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
195
196 public BSScene(string identifier) 196 public BSScene(string identifier)
197 { 197 {
198 m_initialized = false; 198 m_initialized = false;
199 // we are passed the name of the region we're working for.
200 RegionName = identifier;
199 } 201 }
200 202
201 public override void Initialise(IMesher meshmerizer, IConfigSource config) 203 public override void Initialise(IMesher meshmerizer, IConfigSource config)
@@ -213,6 +215,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
213 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 215 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
214 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 216 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
215 217
218 mesher = meshmerizer;
219 _taintedObjects = new List<TaintCallbackEntry>();
220
216 // Enable very detailed logging. 221 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 222 // By creating an empty logger when not logging, the log message invocation code
218 // can be left in and every call doesn't have to check for null. 223 // can be left in and every call doesn't have to check for null.
@@ -225,38 +230,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 230 PhysicsLogging = new Logging.LogWriter();
226 } 231 }
227 232
228 // Get the version of the DLL 233 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 234 m_DebugLogCallbackHandle = null;
230 // BulletSimVersion = BulletSimAPI.GetVersion();
231 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
232
233 // if Debug, enable logging from the unmanaged code
234 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 235 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 236 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 237 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 238 if (PhysicsLogging.Enabled)
239 // The handle is saved in a variable to make sure it doesn't get freed after this call
238 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); 240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 241 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 242 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
241 // the handle is saved in a variable to make sure it doesn't get freed after this call
242 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
243 } 243 }
244 244
245 _taintedObjects = new List<TaintCallbackEntry>(); 245 // Get the version of the DLL
246 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
247 // BulletSimVersion = BulletSimAPI.GetVersion();
248 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 249
247 mesher = meshmerizer; 250 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 251 // a child in a mega-region.
252 // Turns out that Bullet really doesn't care about the extents of the simulated
253 // area. It tracks active objects no matter where they are.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 254 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
250 255
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 256 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 257 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 258 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 259 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
260 m_DebugLogCallbackHandle);
255 261
256 // Initialization to support the transition to a new API which puts most of the logic 262 // Initialization to support the transition to a new API which puts most of the logic
257 // into the C# code so it is easier to modify and add to. 263 // into the C# code so it is easier to modify and add to.
258 m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); 264 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
259 m_constraintCollection = new BSConstraintCollection(World); 265
266 Constraints = new BSConstraintCollection(World);
267
268 TerrainManager = new BSTerrainManager(this);
269 TerrainManager.CreateInitialGroundPlaneAndTerrain();
260 270
261 m_initialized = true; 271 m_initialized = true;
262 } 272 }
@@ -281,10 +291,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 291 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 292 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 293 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 294 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 295 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 296 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 297 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
298
299 // Do any replacements in the parameters
300 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 301 }
289 } 302 }
290 } 303 }
@@ -316,6 +329,38 @@ public class BSScene : PhysicsScene, IPhysicsParameters
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 329 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
317 } 330 }
318 331
332 public override void Dispose()
333 {
334 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
335
336 // make sure no stepping happens while we're deleting stuff
337 m_initialized = false;
338
339 TerrainManager.ReleaseGroundPlaneAndTerrain();
340
341 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
342 {
343 kvp.Value.Destroy();
344 }
345 PhysObjects.Clear();
346
347 // Now that the prims are all cleaned up, there should be no constraints left
348 if (Constraints != null)
349 {
350 Constraints.Dispose();
351 Constraints = null;
352 }
353
354 // Anything left in the unmanaged code should be cleaned out
355 BulletSimAPI.Shutdown(WorldID);
356
357 // Not logging any more
358 PhysicsLogging.Close();
359 }
360 #endregion // Construction and Initialization
361
362 #region Prim and Avatar addition and removal
363
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 364 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 365 {
321 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 366 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -329,7 +374,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 374 if (!m_initialized) return null;
330 375
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 376 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 377 lock (PhysObjects) PhysObjects.Add(localID, actor);
378
379 // TODO: Remove kludge someday.
380 // We must generate a collision for avatars whether they collide or not.
381 // This is required by OpenSim to update avatar animations, etc.
382 lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor);
383
333 return actor; 384 return actor;
334 } 385 }
335 386
@@ -344,7 +395,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 395 {
345 try 396 try
346 { 397 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 398 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
399 // Remove kludge someday
400 lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Remove(bsactor);
348 } 401 }
349 catch (Exception e) 402 catch (Exception e)
350 { 403 {
@@ -362,11 +415,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 415 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 416 if (bsprim != null)
364 { 417 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 418 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 419 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 420 try
368 { 421 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 422 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 423 }
371 catch (Exception e) 424 catch (Exception e)
372 { 425 {
@@ -388,10 +441,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 441
389 if (!m_initialized) return null; 442 if (!m_initialized) return null;
390 443
391 // DetailLog("{0},AddPrimShape,call", localID); 444 DetailLog("{0},AddPrimShape,call", localID);
392 445
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 446 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 447 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 448 return prim;
396 } 449 }
397 450
@@ -400,6 +453,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 // information call is not needed. 453 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 454 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 455
456 #endregion // Prim and Avatar addition and removal
457
458 #region Simulation
403 // Simulate one timestep 459 // Simulate one timestep
404 public override float Simulate(float timeStep) 460 public override float Simulate(float timeStep)
405 { 461 {
@@ -408,18 +464,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 464 int collidersCount = 0;
409 IntPtr collidersPtr; 465 IntPtr collidersPtr;
410 466
411 LastSimulatedTimestep = timeStep;
412
413 // prevent simulation until we've been initialized 467 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 468 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 469
418 // update the prim states while we know the physics engine is not busy 470 // update the prim states while we know the physics engine is not busy
471 int numTaints = _taintedObjects.Count;
419 ProcessTaints(); 472 ProcessTaints();
420 473
421 // Some of the prims operate with special vehicle properties 474 // Some of the prims operate with special vehicle properties
422 ProcessVehicles(timeStep); 475 ProcessVehicles(timeStep);
476 numTaints += _taintedObjects.Count;
423 ProcessTaints(); // the vehicles might have added taints 477 ProcessTaints(); // the vehicles might have added taints
424 478
425 // step the physical world one interval 479 // step the physical world one interval
@@ -427,15 +481,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
427 int numSubSteps = 0; 481 int numSubSteps = 0;
428 try 482 try
429 { 483 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 484 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 485 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 486 DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}",
487 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
433 } 488 }
434 catch (Exception e) 489 catch (Exception e)
435 { 490 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 491 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
437 // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 492 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 493 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
494 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
495 updatedEntityCount = 0;
439 collidersCount = 0; 496 collidersCount = 0;
440 } 497 }
441 498
@@ -443,7 +500,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
443 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 500 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 501
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 502 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 503 SimulationNowTime = Util.EnvironmentTickCount();
504
505 // This is a kludge to get avatar movement updates.
506 // ODE sends collisions for avatars even if there are have been no collisions. This updates
507 // avatar animations and stuff.
508 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
509 m_objectsWithCollisions = new HashSet<BSPhysObject>(m_avatarsWithCollisions);
447 510
448 // If there were collisions, process them by sending the event to the prim. 511 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 512 // Collisions must be processed before updates.
@@ -462,19 +525,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
462 525
463 // The above SendCollision's batch up the collisions on the objects. 526 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 527 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 528 foreach (BSPhysObject bsp in m_objectsWithCollisions)
466 bsp.SendCollisions(); 529 bsp.SendCollisions();
467 m_primsWithCollisions.Clear(); 530 m_objectsWithCollisions.Clear();
468
469 // This is a kludge to get avatar movement updated.
470 // Don't send collisions only if there were collisions -- send everytime.
471 // ODE sends collisions even if there are none and this is used to update
472 // avatar animations and stuff.
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions)
474 // bsc.SendCollisions();
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
476 kvp.Value.SendCollisions();
477 m_avatarsWithCollisions.Clear();
478 531
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 532 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 533 if (updatedEntityCount > 0)
@@ -482,17 +535,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 535 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 536 {
484 EntityProperties entprop = m_updateArray[ii]; 537 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 538 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 539 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
487 {
488 prim.UpdateProperties(entprop);
489 continue;
490 }
491 BSCharacter actor;
492 if (m_avatars.TryGetValue(entprop.ID, out actor))
493 { 540 {
494 actor.UpdateProperties(entprop); 541 pobj.UpdateProperties(entprop);
495 continue;
496 } 542 }
497 } 543 }
498 } 544 }
@@ -506,79 +552,59 @@ public class BSScene : PhysicsScene, IPhysicsParameters
506 } 552 }
507 } 553 }
508 554
509 // this is a waste since the outside routine also calcuates the physics simulation 555 // The physics engine returns the number of milliseconds it simulated this call.
510 // period. TODO: There should be a way of computing physics frames from simulator computation. 556 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); 557 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
512 // return (timeStep * (float)simulateTotalTime); 558 return numSubSteps * m_fixedTimeStep;
513
514 // TODO: FIX THIS: fps calculation possibly wrong.
515 // This calculation says 1/timeStep is the ideal frame rate. Any time added to
516 // that by the physics simulation gives a slower frame rate.
517 long totalSimulationTime = Util.EnvironmentTickCountSubtract(simulateStartTime);
518 if (totalSimulationTime >= timeStep)
519 return 0;
520 return 1f / (timeStep + totalSimulationTime);
521 } 559 }
522 560
523 // Something has collided 561 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 562 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 563 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 564 if (localID <= TerrainManager.HighestTerrainID)
527 { 565 {
528 return; // don't send collisions to the terrain 566 return; // don't send collisions to the terrain
529 } 567 }
530 568
531 ActorTypes type = ActorTypes.Prim; 569 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 570 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 571 {
534 else if (m_avatars.ContainsKey(collidingWith)) 572 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent;
536
537 BSPrim prim;
538 if (m_prims.TryGetValue(localID, out prim)) {
539 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
540 m_primsWithCollisions.Add(prim);
541 return; 573 return;
542 } 574 }
543 BSCharacter actor; 575
544 if (m_avatars.TryGetValue(localID, out actor)) { 576 // The terrain is not in the physical object list so 'collidee'
545 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 577 // can be null when Collide() is called.
546 m_avatarsWithCollisions.Add(actor); 578 BSPhysObject collidee = null;
547 return; 579 PhysObjects.TryGetValue(collidingWith, out collidee);
580
581 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
582
583 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
584 {
585 // If a collision was posted, remember to send it to the simulator
586 m_objectsWithCollisions.Add(collider);
548 } 587 }
588
549 return; 589 return;
550 } 590 }
551 591
552 public override void GetResults() { } 592 #endregion // Simulation
553 593
554 public override void SetTerrain(float[] heightMap) { 594 public override void GetResults() { }
555 m_heightMap = heightMap;
556 this.TaintedObject("BSScene.SetTerrain", delegate()
557 {
558 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
559 });
560 }
561 595
562 // Someday we will have complex terrain with caves and tunnels 596 #region Terrain
563 // For the moment, it's flat and convex
564 public float GetTerrainHeightAtXYZ(Vector3 loc)
565 {
566 return GetTerrainHeightAtXY(loc.X, loc.Y);
567 }
568 597
569 public float GetTerrainHeightAtXY(float tX, float tY) 598 public override void SetTerrain(float[] heightMap) {
570 { 599 TerrainManager.SetTerrain(heightMap);
571 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
572 return 30;
573 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
574 } 600 }
575 601
576 public override void SetWaterLevel(float baseheight) 602 public override void SetWaterLevel(float baseheight)
577 { 603 {
578 m_waterLevel = baseheight; 604 m_waterLevel = baseheight;
579 // TODO: pass to physics engine so things will float?
580 } 605 }
581 public float GetWaterLevel() 606 // Someday....
607 public float GetWaterLevelAtXYZ(Vector3 loc)
582 { 608 {
583 return m_waterLevel; 609 return m_waterLevel;
584 } 610 }
@@ -588,39 +614,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 614 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
589 } 615 }
590 616
591 public override void Dispose() 617 // Although no one seems to check this, I do support combining.
618 public override bool SupportsCombining()
592 { 619 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 620 return TerrainManager.SupportsCombining();
594 621 }
595 // make sure no stepping happens while we're deleting stuff 622 // This call says I am a child to region zero in a mega-region. 'pScene' is that
596 m_initialized = false; 623 // of region zero, 'offset' is my offset from regions zero's origin, and
597 624 // 'extents' is the largest XY that is handled in my region.
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 625 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
599 { 626 {
600 kvp.Value.Destroy(); 627 TerrainManager.Combine(pScene, offset, extents);
601 } 628 }
602 m_avatars.Clear();
603
604 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
605 {
606 kvp.Value.Destroy();
607 }
608 m_prims.Clear();
609
610 // Now that the prims are all cleaned up, there should be no constraints left
611 if (m_constraintCollection != null)
612 {
613 m_constraintCollection.Dispose();
614 m_constraintCollection = null;
615 }
616
617 // Anything left in the unmanaged code should be cleaned out
618 BulletSimAPI.Shutdown(WorldID);
619 629
620 // Not logging any more 630 // Unhook all the combining that I know about.
621 PhysicsLogging.Close(); 631 public override void UnCombine(PhysicsScene pScene)
632 {
633 TerrainManager.UnCombine(pScene);
622 } 634 }
623 635
636 #endregion // Terrain
637
624 public override Dictionary<uint, float> GetTopColliders() 638 public override Dictionary<uint, float> GetTopColliders()
625 { 639 {
626 return new Dictionary<uint, float>(); 640 return new Dictionary<uint, float>();
@@ -628,121 +642,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
628 642
629 public override bool IsThreaded { get { return false; } } 643 public override bool IsThreaded { get { return false; } }
630 644
631 /// <summary>
632 /// Routine to figure out if we need to mesh this prim with our mesher
633 /// </summary>
634 /// <param name="pbs"></param>
635 /// <returns>true if the prim needs meshing</returns>
636 public bool NeedsMeshing(PrimitiveBaseShape pbs)
637 {
638 // most of this is redundant now as the mesher will return null if it cant mesh a prim
639 // but we still need to check for sculptie meshing being enabled so this is the most
640 // convenient place to do it for now...
641
642 // int iPropertiesNotSupportedDefault = 0;
643
644 if (pbs.SculptEntry && !_meshSculptedPrim)
645 {
646 // Render sculpties as boxes
647 return false;
648 }
649
650 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
651 // can use an internal representation for the prim
652 if (!_forceSimplePrimMeshing)
653 {
654 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
655 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
656 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
657 {
658
659 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
660 && pbs.ProfileHollow == 0
661 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
662 && pbs.PathBegin == 0 && pbs.PathEnd == 0
663 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
664 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
665 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
666 {
667 return false;
668 }
669 }
670 }
671
672 /* TODO: verify that the mesher will now do all these shapes
673 if (pbs.ProfileHollow != 0)
674 iPropertiesNotSupportedDefault++;
675
676 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
677 iPropertiesNotSupportedDefault++;
678
679 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
680 iPropertiesNotSupportedDefault++;
681
682 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
683 iPropertiesNotSupportedDefault++;
684
685 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
686 iPropertiesNotSupportedDefault++;
687
688 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
689 iPropertiesNotSupportedDefault++;
690
691 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
692 iPropertiesNotSupportedDefault++;
693
694 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
695 iPropertiesNotSupportedDefault++;
696
697 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
698 iPropertiesNotSupportedDefault++;
699
700 // test for torus
701 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
702 {
703 if (pbs.PathCurve == (byte)Extrusion.Curve1)
704 {
705 iPropertiesNotSupportedDefault++;
706 }
707 }
708 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
709 {
710 if (pbs.PathCurve == (byte)Extrusion.Straight)
711 {
712 iPropertiesNotSupportedDefault++;
713 }
714 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
715 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
716 {
717 iPropertiesNotSupportedDefault++;
718 }
719 }
720 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
721 {
722 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
723 {
724 iPropertiesNotSupportedDefault++;
725 }
726 }
727 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
728 {
729 if (pbs.PathCurve == (byte)Extrusion.Straight)
730 {
731 iPropertiesNotSupportedDefault++;
732 }
733 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
734 {
735 iPropertiesNotSupportedDefault++;
736 }
737 }
738 if (iPropertiesNotSupportedDefault == 0)
739 {
740 return false;
741 }
742 */
743 return true;
744 }
745
746 // Calls to the PhysicsActors can't directly call into the physics engine 645 // Calls to the PhysicsActors can't directly call into the physics engine
747 // because it might be busy. We delay changes to a known time. 646 // because it might be busy. We delay changes to a known time.
748 // We rely on C#'s closure to save and restore the context for the delegate. 647 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -751,7 +650,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
751 if (!m_initialized) return; 650 if (!m_initialized) return;
752 651
753 lock (_taintLock) 652 lock (_taintLock)
653 {
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 654 _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
655 }
656
755 return; 657 return;
756 } 658 }
757 659
@@ -830,14 +732,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
830 // no locking because only called when physics engine is not busy 732 // no locking because only called when physics engine is not busy
831 private void ProcessVehicles(float timeStep) 733 private void ProcessVehicles(float timeStep)
832 { 734 {
833 foreach (BSPrim prim in m_vehicles) 735 foreach (BSPhysObject pobj in m_vehicles)
834 { 736 {
835 prim.StepVehicle(timeStep); 737 pobj.StepVehicle(timeStep);
836 } 738 }
837 } 739 }
838 #endregion Vehicles 740 #endregion Vehicles
839 741
840 #region Parameters 742 #region INI and command line parameter processing
841 743
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 744 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 745 delegate float ParamGet(BSScene scene);
@@ -888,25 +790,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 790 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 791 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 792 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 793 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 794 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 795 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 796 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 797 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 798 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 799 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 800 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
899 801
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 802 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 803 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 804 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 805 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 806 (s,p,l,v) => { s.MeshLOD = v; } ),
905 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", 807 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
808 16f,
809 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
810 (s) => { return s.MeshMegaPrimLOD; },
811 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
812 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
813 10f,
814 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
815 (s) => { return s.MeshMegaPrimThreshold; },
816 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
817 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 818 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 819 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 820 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 821 (s,p,l,v) => { s.SculptLOD = v; } ),
910 822
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 823 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 824 10f,
@@ -930,9 +842,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 842 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 843 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 844 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 845 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 846 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 847 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 848
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 849 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 850 2200f,
@@ -976,42 +888,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
976 0f, 888 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 889 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 890 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 891 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ),
980 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 892 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 893 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 894 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 895 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 896 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ),
985 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 897 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 898 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 899 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 900 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 901 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ),
990 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 902 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 903 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 904 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 905 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 906 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
995 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 907 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 908 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 909 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 910 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 911 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
1000 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 912 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 913 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 914 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 915 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 916 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 917 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 918 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 919 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 920 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 921 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 922 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 923 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 924 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 925 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 926 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
1015 927
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 928 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 929 0.5f,
@@ -1029,35 +941,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1029 (s) => { return s.m_params[0].terrainRestitution; }, 941 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 942 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
1031 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 943 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 944 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 945 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 946 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 947 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1036 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 948 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 949 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 950 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 951 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 952 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 953 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 954 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 955 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 956 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 957 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1046 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", 958 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1047 0.37f, 959 0.37f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 960 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 961 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 962 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
1051 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 963 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 964 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 965 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 966 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 967 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1056 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 968 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 969 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 970 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 971 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 973
1062 974
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 975 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
@@ -1121,8 +1033,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1033 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1034 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1035 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1124 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0", 1036 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1037 0.1f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1038 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1039 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1040 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
@@ -1131,18 +1043,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1043 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1044 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1045 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1046 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1047 40,
1048 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1050 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1051
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1052 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1053 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1054 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1055 (s) => { return (float)s.m_detailedStatsStep; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1056 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
1140 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1141 ConfigurationParameters.numericFalse,
1142 (s,cf,p,v) => { s.ShouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1143 (s) => { return s.NumericBool(s.ShouldDebugLog); },
1144 (s,p,l,v) => { s.ShouldDebugLog = s.BoolNumeric(v); } ),
1145
1146 }; 1057 };
1147 1058
1148 // Convert a boolean to our numeric true and false values 1059 // Convert a boolean to our numeric true and false values
@@ -1200,6 +1111,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1111
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1112 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1113
1114 // This creates an array in the correct format for returning the list of
1115 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1116 private void BuildParameterTable()
1204 { 1117 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1118 if (SettableParameters.Length < ParameterDefinitions.Length)
@@ -1250,18 +1163,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1250 } 1163 }
1251 1164
1252 // check to see if we are updating a parameter for a particular or all of the prims 1165 // check to see if we are updating a parameter for a particular or all of the prims
1253 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) 1166 protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
1254 {
1255 List<uint> operateOn;
1256 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
1257 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1258 }
1259
1260 // check to see if we are updating a parameter for a particular or all of the avatars
1261 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
1262 { 1167 {
1263 List<uint> operateOn; 1168 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1169 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val); 1170 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 } 1171 }
1267 1172
@@ -1284,7 +1189,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1189 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs) 1190 foreach (uint lID in objectIDs)
1286 { 1191 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); 1192 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1288 } 1193 }
1289 }); 1194 });
1290 break; 1195 break;
@@ -1302,7 +1207,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1302 string xparm = parm.ToLower(); 1207 string xparm = parm.ToLower();
1303 float xval = val; 1208 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1209 TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1210 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
1306 }); 1211 });
1307 } 1212 }
1308 1213