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.cs774
1 files changed, 373 insertions, 401 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..2c3c481 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,33 +39,27 @@ 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 42// Test sculpties (verified that they don't work)
43// Test with multiple regions in one simulator
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably 43// Compute physics FPS reasonably
47// Based on material, set density and friction 44// Based on material, set density and friction
48// More efficient memory usage when passing hull information from BSPrim to BulletSim 45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
49// Move all logic out of the C++ code and into the C# code for easier future modifications.
50// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
51// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
52// At the moment, physical and phantom causes object to drop through the terrain 48// At the moment, physical and phantom causes object to drop through the terrain
53// Physical phantom objects and related typing (collision options ) 49// Physical phantom objects and related typing (collision options )
54// Use collision masks for collision with terrain and phantom objects
55// Check out llVolumeDetect. Must do something for that. 50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim
56// Should prim.link() and prim.delink() membership checking happen at taint time? 53// 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. 54// 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
59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 55// 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 56// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 57// 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. 58// 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? 59// Add PID movement operations. What does ScenePresence.MoveToTarget do?
66// Check terrain size. 128 or 127? 60// Check terrain size. 128 or 127?
67// Raycast 61// Raycast
68// 62//
69namespace OpenSim.Region.Physics.BulletSPlugin 63namespace OpenSim.Region.Physics.BulletSPlugin
70{ 64{
71public class BSScene : PhysicsScene, IPhysicsParameters 65public class BSScene : PhysicsScene, IPhysicsParameters
@@ -73,62 +67,56 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 68 private static readonly string LogHeader = "[BULLETS SCENE]";
75 69
76 public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } 70 // The name of the region we're working for.
71 public string RegionName { get; private set; }
77 72
78 public string BulletSimVersion = "?"; 73 public string BulletSimVersion = "?";
79 74
80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 75 public Dictionary<uint, BSPhysObject> PhysObjects;
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 76 public BSShapeCollection Shapes;
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>();
84 private List<BSPrim> m_vehicles = new List<BSPrim>();
85 private float[] m_heightMap;
86 private float m_waterLevel;
87 private uint m_worldID;
88 public uint WorldID { get { return m_worldID; } }
89 77
90 // let my minuions use my logger 78 // Keeping track of the objects with collisions so we can report begin and end of a collision
91 public ILog Logger { get { return m_log; } } 79 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
80 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
81 // Keep track of all the avatars so we can send them a collision event
82 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
92 84
93 private bool m_initialized = false; 85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
94 88
95 private int m_detailedStatsStep = 0; 89 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } }
96 91
97 public IMesher mesher; 92 public IMesher mesher;
98 private float m_meshLOD; 93 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 94 public float MeshLOD { get; private set; }
100 { 95 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 96 public float MeshMegaPrimThreshold { get; private set; }
102 } 97 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 98
109 private BulletSim m_worldSim; 99 public uint WorldID { get; private set; }
110 public BulletSim World 100 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 101
102 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; }
104
105 // Simulation parameters
120 private int m_maxSubSteps; 106 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 107 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
124 110 private int m_taintsToProcessPerStep;
125 public float LastSimulatedTimestep { get; private set; }
126 111
127 // A value of the time now so all the collision and update routines do not have to get their own 112 // A value of the time now so all the collision and update routines do not have to get their own
128 // Set to 'now' just before all the prims and actors are called for collisions and updates 113 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 114 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 115
116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false;
131 118
119 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 120 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 121 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 122 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +125,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 125 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 126 private GCHandle m_updateArrayPinnedHandle;
139 127
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 128 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 129 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
130 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
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,17 +189,24 @@ 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)
202 { 204 {
205 mesher = meshmerizer;
206 _taintedObjects = new List<TaintCallbackEntry>();
207 PhysObjects = new Dictionary<uint, BSPhysObject>();
208 Shapes = new BSShapeCollection(this);
209
203 // Allocate pinned memory to pass parameters. 210 // Allocate pinned memory to pass parameters.
204 m_params = new ConfigurationParameters[1]; 211 m_params = new ConfigurationParameters[1];
205 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 212 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,7 +222,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 222
216 // Enable very detailed logging. 223 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 224 // 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. 225 // can be left in and every call doesn't have to check for null.
219 if (m_physicsLoggingEnabled) 226 if (m_physicsLoggingEnabled)
220 { 227 {
221 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 228 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -225,38 +232,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 232 PhysicsLogging = new Logging.LogWriter();
226 } 233 }
227 234
228 // Get the version of the DLL 235 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 236 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) 237 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 238 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 239 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 240 if (PhysicsLogging.Enabled)
241 // 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); 242 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 243 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 244 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 } 245 }
244 246
245 _taintedObjects = new List<TaintCallbackEntry>(); 247 // Get the version of the DLL
248 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
249 // BulletSimVersion = BulletSimAPI.GetVersion();
250 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 251
247 mesher = meshmerizer; 252 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 253 // a child in a mega-region.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 254 // Bullet actually doesn't care about the extents of the simulated
255 // area. It tracks active objects no matter where they are.
256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
250 257
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 258 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 259 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 260 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 261 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
262 m_DebugLogCallbackHandle);
255 263
256 // Initialization to support the transition to a new API which puts most of the logic 264 // 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. 265 // 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)); 266 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
259 m_constraintCollection = new BSConstraintCollection(World); 267
268 Constraints = new BSConstraintCollection(World);
269
270 TerrainManager = new BSTerrainManager(this);
271 TerrainManager.CreateInitialGroundPlaneAndTerrain();
260 272
261 m_initialized = true; 273 m_initialized = true;
262 } 274 }
@@ -281,10 +293,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 293 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 294 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 295 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 296 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 297 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 298 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 299 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
300
301 // Do any replacements in the parameters
302 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 303 }
289 } 304 }
290 } 305 }
@@ -309,12 +324,50 @@ public class BSScene : PhysicsScene, IPhysicsParameters
309 { 324 {
310 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 325 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
311 } 326 }
312 327
313 // Called directly from unmanaged code so don't do much 328 // Called directly from unmanaged code so don't do much
314 private void BulletLoggerPhysLog(string msg) 329 private void BulletLoggerPhysLog(string msg)
315 { 330 {
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 331 DetailLog("[BULLETS UNMANAGED]:" + msg);
332 }
333
334 public override void Dispose()
335 {
336 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
337
338 // make sure no stepping happens while we're deleting stuff
339 m_initialized = false;
340
341 TerrainManager.ReleaseGroundPlaneAndTerrain();
342
343 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
344 {
345 kvp.Value.Destroy();
346 }
347 PhysObjects.Clear();
348
349 // Now that the prims are all cleaned up, there should be no constraints left
350 if (Constraints != null)
351 {
352 Constraints.Dispose();
353 Constraints = null;
354 }
355
356 if (Shapes != null)
357 {
358 Shapes.Dispose();
359 Shapes = null;
360 }
361
362 // Anything left in the unmanaged code should be cleaned out
363 BulletSimAPI.Shutdown(WorldID);
364
365 // Not logging any more
366 PhysicsLogging.Close();
317 } 367 }
368 #endregion // Construction and Initialization
369
370 #region Prim and Avatar addition and removal
318 371
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 372 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 373 {
@@ -329,7 +382,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 382 if (!m_initialized) return null;
330 383
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 384 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 385 lock (PhysObjects) PhysObjects.Add(localID, actor);
386
387 // TODO: Remove kludge someday.
388 // We must generate a collision for avatars whether they collide or not.
389 // This is required by OpenSim to update avatar animations, etc.
390 lock (m_avatars) m_avatars.Add(actor);
391
333 return actor; 392 return actor;
334 } 393 }
335 394
@@ -344,7 +403,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 403 {
345 try 404 try
346 { 405 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 406 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
407 // Remove kludge someday
408 lock (m_avatars) m_avatars.Remove(bsactor);
348 } 409 }
349 catch (Exception e) 410 catch (Exception e)
350 { 411 {
@@ -362,11 +423,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 423 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 424 if (bsprim != null)
364 { 425 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 426 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 427 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 428 try
368 { 429 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 430 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 431 }
371 catch (Exception e) 432 catch (Exception e)
372 { 433 {
@@ -388,18 +449,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 449
389 if (!m_initialized) return null; 450 if (!m_initialized) return null;
390 451
391 // DetailLog("{0},AddPrimShape,call", localID); 452 DetailLog("{0},AddPrimShape,call", localID);
392 453
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 454 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 455 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 456 return prim;
396 } 457 }
397 458
398 // This is a call from the simulator saying that some physical property has been updated. 459 // This is a call from the simulator saying that some physical property has been updated.
399 // The BulletSim driver senses the changing of relevant properties so this taint 460 // The BulletSim driver senses the changing of relevant properties so this taint
400 // information call is not needed. 461 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 462 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 463
464 #endregion // Prim and Avatar addition and removal
465
466 #region Simulation
403 // Simulate one timestep 467 // Simulate one timestep
404 public override float Simulate(float timeStep) 468 public override float Simulate(float timeStep)
405 { 469 {
@@ -408,34 +472,46 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 472 int collidersCount = 0;
409 IntPtr collidersPtr; 473 IntPtr collidersPtr;
410 474
411 LastSimulatedTimestep = timeStep; 475 int beforeTime = 0;
476 int simTime = 0;
412 477
413 // prevent simulation until we've been initialized 478 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 479 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 480
418 // update the prim states while we know the physics engine is not busy 481 // update the prim states while we know the physics engine is not busy
482 int numTaints = _taintedObjects.Count;
419 ProcessTaints(); 483 ProcessTaints();
420 484
421 // Some of the prims operate with special vehicle properties 485 // Some of the prims operate with special vehicle properties
422 ProcessVehicles(timeStep); 486 ProcessVehicles(timeStep);
487 numTaints += _taintedObjects.Count;
423 ProcessTaints(); // the vehicles might have added taints 488 ProcessTaints(); // the vehicles might have added taints
424 489
425 // step the physical world one interval 490 // step the physical world one interval
426 m_simulationStep++; 491 m_simulationStep++;
427 int numSubSteps = 0; 492 int numSubSteps = 0;
493
494 // DEBUG
495 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
496
428 try 497 try
429 { 498 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 499 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
500
501 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 502 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 503
504 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
505 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
506 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
433 } 507 }
434 catch (Exception e) 508 catch (Exception e)
435 { 509 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 510 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); 511 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 512 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
513 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
514 updatedEntityCount = 0;
439 collidersCount = 0; 515 collidersCount = 0;
440 } 516 }
441 517
@@ -443,7 +519,7 @@ 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 519 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 520
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 521 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 522 SimulationNowTime = Util.EnvironmentTickCount();
447 523
448 // If there were collisions, process them by sending the event to the prim. 524 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 525 // Collisions must be processed before updates.
@@ -460,21 +536,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
460 } 536 }
461 } 537 }
462 538
539 // This is a kludge to get avatar movement updates.
540 // the simulator expects collisions for avatars even if there are have been no collisions. This updates
541 // avatar animations and stuff.
542 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
543 foreach (BSPhysObject bsp in m_avatars)
544 bsp.SendCollisions();
545
463 // The above SendCollision's batch up the collisions on the objects. 546 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 547 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 548 if (ObjectsWithCollisions.Count > 0)
466 bsp.SendCollisions(); 549 {
467 m_primsWithCollisions.Clear(); 550 foreach (BSPhysObject bsp in ObjectsWithCollisions)
551 if (!m_avatars.Contains(bsp)) // don't call avatars twice
552 if (!bsp.SendCollisions())
553 {
554 // If the object is done colliding, see that it's removed from the colliding list
555 ObjectsWithNoMoreCollisions.Add(bsp);
556 }
557 }
468 558
469 // This is a kludge to get avatar movement updated. 559 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
470 // Don't send collisions only if there were collisions -- send everytime. 560 // Not done above because it is inside an iteration of ObjectWithCollisions.
471 // ODE sends collisions even if there are none and this is used to update 561 if (ObjectsWithNoMoreCollisions.Count > 0)
472 // avatar animations and stuff. 562 {
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 563 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
474 // bsc.SendCollisions(); 564 ObjectsWithCollisions.Remove(po);
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 565 ObjectsWithNoMoreCollisions.Clear();
476 kvp.Value.SendCollisions(); 566 }
477 m_avatarsWithCollisions.Clear();
478 567
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 568 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 569 if (updatedEntityCount > 0)
@@ -482,145 +571,98 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 571 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 572 {
484 EntityProperties entprop = m_updateArray[ii]; 573 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 574 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 575 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 { 576 {
494 actor.UpdateProperties(entprop); 577 pobj.UpdateProperties(entprop);
495 continue;
496 } 578 }
497 } 579 }
498 } 580 }
499 581
500 // If enabled, call into the physics engine to dump statistics 582 // The physics engine returns the number of milliseconds it simulated this call.
501 if (m_detailedStatsStep > 0) 583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
502 { 584 // We multiply by 45 to give a recognizable running rate (45 or less).
503 if ((m_simulationStep % m_detailedStatsStep) == 0) 585 return numSubSteps * m_fixedTimeStep * 1000 * 45;
504 { 586 // return timeStep * 1000 * 45;
505 BulletSimAPI.DumpBulletStatistics();
506 }
507 }
508
509 // this is a waste since the outside routine also calcuates the physics simulation
510 // period. TODO: There should be a way of computing physics frames from simulator computation.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime);
512 // return (timeStep * (float)simulateTotalTime);
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 } 587 }
522 588
523 // Something has collided 589 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 590 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 591 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 592 if (localID <= TerrainManager.HighestTerrainID)
527 { 593 {
528 return; // don't send collisions to the terrain 594 return; // don't send collisions to the terrain
529 } 595 }
530 596
531 ActorTypes type = ActorTypes.Prim; 597 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 598 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 599 {
534 else if (m_avatars.ContainsKey(collidingWith)) 600 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent; 601 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
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; 602 return;
542 } 603 }
543 BSCharacter actor; 604
544 if (m_avatars.TryGetValue(localID, out actor)) { 605 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
545 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 606 BSPhysObject collidee = null;
546 m_avatarsWithCollisions.Add(actor); 607 PhysObjects.TryGetValue(collidingWith, out collidee);
547 return; 608
609 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
610
611 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
612 {
613 // If a collision was posted, remember to send it to the simulator
614 ObjectsWithCollisions.Add(collider);
548 } 615 }
616
549 return; 617 return;
550 } 618 }
551 619
552 public override void GetResults() { } 620 #endregion // Simulation
553 621
554 public override void SetTerrain(float[] heightMap) { 622 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 623
562 // Someday we will have complex terrain with caves and tunnels 624 #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 625
569 public float GetTerrainHeightAtXY(float tX, float tY) 626 public override void SetTerrain(float[] heightMap) {
570 { 627 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 } 628 }
575 629
576 public override void SetWaterLevel(float baseheight) 630 public override void SetWaterLevel(float baseheight)
577 { 631 {
578 m_waterLevel = baseheight; 632 m_waterLevel = baseheight;
579 // TODO: pass to physics engine so things will float?
580 } 633 }
581 public float GetWaterLevel() 634 // Someday....
635 public float GetWaterLevelAtXYZ(Vector3 loc)
582 { 636 {
583 return m_waterLevel; 637 return m_waterLevel;
584 } 638 }
585 639
586 public override void DeleteTerrain() 640 public override void DeleteTerrain()
587 { 641 {
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 642 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
589 } 643 }
590 644
591 public override void Dispose() 645 // Although no one seems to check this, I do support combining.
646 public override bool SupportsCombining()
592 { 647 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 648 return TerrainManager.SupportsCombining();
594 649 }
595 // make sure no stepping happens while we're deleting stuff 650 // This call says I am a child to region zero in a mega-region. 'pScene' is that
596 m_initialized = false; 651 // of region zero, 'offset' is my offset from regions zero's origin, and
597 652 // 'extents' is the largest XY that is handled in my region.
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 653 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
599 { 654 {
600 kvp.Value.Destroy(); 655 TerrainManager.Combine(pScene, offset, extents);
601 } 656 }
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 657
620 // Not logging any more 658 // Unhook all the combining that I know about.
621 PhysicsLogging.Close(); 659 public override void UnCombine(PhysicsScene pScene)
660 {
661 TerrainManager.UnCombine(pScene);
622 } 662 }
623 663
664 #endregion // Terrain
665
624 public override Dictionary<uint, float> GetTopColliders() 666 public override Dictionary<uint, float> GetTopColliders()
625 { 667 {
626 return new Dictionary<uint, float>(); 668 return new Dictionary<uint, float>();
@@ -628,121 +670,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
628 670
629 public override bool IsThreaded { get { return false; } } 671 public override bool IsThreaded { get { return false; } }
630 672
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 673 // 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. 674 // 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. 675 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -751,7 +678,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
751 if (!m_initialized) return; 678 if (!m_initialized) return;
752 679
753 lock (_taintLock) 680 lock (_taintLock)
681 {
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 682 _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
683 }
684
755 return; 685 return;
756 } 686 }
757 687
@@ -763,6 +693,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
763 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
764 { 694 {
765 // swizzle a new list into the list location so we can process what's there 695 // swizzle a new list into the list location so we can process what's there
696 int taintCount = m_taintsToProcessPerStep;
697 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
698 while (_taintedObjects.Count > 0 && taintCount-- > 0)
699 {
700 bool gotOne = false;
701 lock (_taintLock)
702 {
703 if (_taintedObjects.Count > 0)
704 {
705 oneCallback = _taintedObjects[0];
706 _taintedObjects.RemoveAt(0);
707 gotOne = true;
708 }
709 }
710 if (gotOne)
711 {
712 try
713 {
714 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
715 oneCallback.callback();
716 }
717 catch (Exception e)
718 {
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 }
721 }
722 }
723 /*
724 // swizzle a new list into the list location so we can process what's there
766 List<TaintCallbackEntry> oldList; 725 List<TaintCallbackEntry> oldList;
767 lock (_taintLock) 726 lock (_taintLock)
768 { 727 {
@@ -774,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
774 { 733 {
775 try 734 try
776 { 735 {
736 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
777 tcbe.callback(); 737 tcbe.callback();
778 } 738 }
779 catch (Exception e) 739 catch (Exception e)
@@ -782,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
782 } 742 }
783 } 743 }
784 oldList.Clear(); 744 oldList.Clear();
745 */
785 } 746 }
786 } 747 }
787 748
@@ -789,13 +750,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
789 750
790 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 751 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
791 { 752 {
792 if (newType == Vehicle.TYPE_NONE) 753 RemoveVehiclePrim(vehic);
793 { 754 if (newType != Vehicle.TYPE_NONE)
794 RemoveVehiclePrim(vehic);
795 }
796 else
797 { 755 {
798 // make it so the scene will call us each tick to do vehicle things 756 // make it so the scene will call us each tick to do vehicle things
799 AddVehiclePrim(vehic); 757 AddVehiclePrim(vehic);
800 } 758 }
801 } 759 }
@@ -827,17 +785,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
827 } 785 }
828 786
829 // Some prims have extra vehicle actions 787 // Some prims have extra vehicle actions
830 // no locking because only called when physics engine is not busy 788 // Called at taint time!
831 private void ProcessVehicles(float timeStep) 789 private void ProcessVehicles(float timeStep)
832 { 790 {
833 foreach (BSPrim prim in m_vehicles) 791 foreach (BSPhysObject pobj in m_vehicles)
834 { 792 {
835 prim.StepVehicle(timeStep); 793 pobj.StepVehicle(timeStep);
836 } 794 }
837 } 795 }
838 #endregion Vehicles 796 #endregion Vehicles
839 797
840 #region Parameters 798 #region INI and command line parameter processing
841 799
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 800 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 801 delegate float ParamGet(BSScene scene);
@@ -869,7 +827,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
869 // getters and setters. 827 // getters and setters.
870 // It is easiest to find an existing definition and copy it. 828 // It is easiest to find an existing definition and copy it.
871 // Parameter values are floats. Booleans are converted to a floating value. 829 // Parameter values are floats. Booleans are converted to a floating value.
872 // 830 //
873 // A ParameterDefn() takes the following parameters: 831 // A ParameterDefn() takes the following parameters:
874 // -- the text name of the parameter. This is used for console input and ini file. 832 // -- the text name of the parameter. This is used for console input and ini file.
875 // -- a short text description of the parameter. This shows up in the console listing. 833 // -- a short text description of the parameter. This shows up in the console listing.
@@ -888,25 +846,40 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 846 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 847 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 848 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 849 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 850 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 851 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 852 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 853 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 854 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 855 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 856 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
857 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
858 ConfigurationParameters.numericTrue,
859 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
860 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
861 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
899 862
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 863 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 864 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 865 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 866 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 867 (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)", 868 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
869 16f,
870 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
871 (s) => { return s.MeshMegaPrimLOD; },
872 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
873 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
874 10f,
875 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
876 (s) => { return s.MeshMegaPrimThreshold; },
877 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
878 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 879 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 880 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 881 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 882 (s,p,l,v) => { s.SculptLOD = v; } ),
910 883
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 884 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 885 10f,
@@ -928,11 +901,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
928 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 901 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
929 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 902 (s) => { return (float)s.m_maxUpdatesPerFrame; },
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 903 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
904 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
905 100f,
906 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
907 (s) => { return (float)s.m_taintsToProcessPerStep; },
908 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 909 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 910 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 911 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 912 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 913 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 914
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 915 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 916 2200f,
@@ -976,42 +954,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
976 0f, 954 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 955 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 956 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 957 (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)", 958 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 959 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 960 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 961 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 962 (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", 963 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 964 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 965 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 966 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 967 (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", 968 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 969 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 970 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 971 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 972 (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", 973 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 974 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 975 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 976 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 977 (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)" , 978 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 979 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 980 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 981 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 982 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 983 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 984 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 985 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 986 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 987 (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" , 988 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 989 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 990 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 991 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 992 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
1015 993
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 994 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 995 0.5f,
@@ -1029,44 +1007,44 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1029 (s) => { return s.m_params[0].terrainRestitution; }, 1007 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 1008 (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.", 1009 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 1010 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1011 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 1012 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 1013 (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.", 1014 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 1015 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 1016 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 1017 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 1018 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 1019 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 1020 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 1021 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 1022 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 1023 (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", 1024 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1047 0.37f, 1025 0.37f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 1026 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 1027 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 1028 (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", 1029 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 1030 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1031 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 1032 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 1033 (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", 1034 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 1035 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 1036 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1037 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1038 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 1039
1062 1040
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1041 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1064 0f, // zero to disable 1042 0f,
1065 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, 1043 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, 1044 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1067 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), 1045 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1068 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", 1046 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1069 0f, // zero to disable 1047 0f,
1070 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, 1048 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, 1049 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1072 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), 1050 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
@@ -1081,12 +1059,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1081 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, 1059 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1082 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), 1060 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1083 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", 1061 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1084 ConfigurationParameters.numericFalse, 1062 ConfigurationParameters.numericTrue,
1085 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1063 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1086 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, 1064 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1087 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1065 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1088 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1066 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1089 ConfigurationParameters.numericFalse, 1067 ConfigurationParameters.numericTrue,
1090 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1068 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1091 (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, 1069 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1092 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1070 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1121,28 +1099,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1099 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1100 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1101 (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", 1102 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1103 0.001f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1104 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1105 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1106 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1129 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1107 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1130 0.2f, 1108 0.8f,
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1109 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1110 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1111 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1112 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1113 40,
1114 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1115 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1116 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1117
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1118 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1119 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1120 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1121 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1122 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (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 }; 1123 };
1147 1124
1148 // Convert a boolean to our numeric true and false values 1125 // Convert a boolean to our numeric true and false values
@@ -1200,11 +1177,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1177
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1178 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1179
1180 // This creates an array in the correct format for returning the list of
1181 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1182 private void BuildParameterTable()
1204 { 1183 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1184 if (SettableParameters.Length < ParameterDefinitions.Length)
1206 { 1185 {
1207
1208 List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); 1186 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1209 for (int ii = 0; ii < ParameterDefinitions.Length; ii++) 1187 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1210 { 1188 {
@@ -1250,18 +1228,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1250 } 1228 }
1251 1229
1252 // check to see if we are updating a parameter for a particular or all of the prims 1230 // 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) 1231 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 { 1232 {
1263 List<uint> operateOn; 1233 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1234 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val); 1235 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 } 1236 }
1267 1237
@@ -1284,11 +1254,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1254 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs) 1255 foreach (uint lID in objectIDs)
1286 { 1256 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); 1257 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1288 } 1258 }
1289 }); 1259 });
1290 break; 1260 break;
1291 default: 1261 default:
1292 // setting only one localID 1262 // setting only one localID
1293 TaintedUpdateParameter(parm, localID, val); 1263 TaintedUpdateParameter(parm, localID, val);
1294 break; 1264 break;
@@ -1302,7 +1272,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1302 string xparm = parm.ToLower(); 1272 string xparm = parm.ToLower();
1303 float xval = val; 1273 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1274 TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1275 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
1306 }); 1276 });
1307 } 1277 }
1308 1278
@@ -1330,6 +1300,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1330 public void DetailLog(string msg, params Object[] args) 1300 public void DetailLog(string msg, params Object[] args)
1331 { 1301 {
1332 PhysicsLogging.Write(msg, args); 1302 PhysicsLogging.Write(msg, args);
1303 // Add the Flush() if debugging crashes to get all the messages written out.
1304 // PhysicsLogging.Flush();
1333 } 1305 }
1334 // used to fill in the LocalID when there isn't one 1306 // used to fill in the LocalID when there isn't one
1335 public const string DetailLogZero = "0000000000"; 1307 public const string DetailLogZero = "0000000000";