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.cs686
1 files changed, 313 insertions, 373 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..0cf8c91 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,33 +39,28 @@ 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// Move all logic out of the C++ code and into the C# code for easier future modifications.
43// Test with multiple regions in one simulator 43// Test sculpties (verified that they don't work)
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably 44// Compute physics FPS reasonably
47// Based on material, set density and friction 45// Based on material, set density and friction
48// More efficient memory usage when passing hull information from BSPrim to BulletSim 46// 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? 47// 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) 48// 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 49// At the moment, physical and phantom causes object to drop through the terrain
53// Physical phantom objects and related typing (collision options ) 50// 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. 51// Check out llVolumeDetect. Must do something for that.
52// Use collision masks for collision with terrain and phantom objects
53// 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? 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. 55// 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 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?
67// Raycast 62// Raycast
68// 63//
69namespace OpenSim.Region.Physics.BulletSPlugin 64namespace OpenSim.Region.Physics.BulletSPlugin
70{ 65{
71public class BSScene : PhysicsScene, IPhysicsParameters 66public class BSScene : PhysicsScene, IPhysicsParameters
@@ -73,62 +68,59 @@ 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;
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 77 public BSShapeCollection Shapes;
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); 78
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>(); 79 // Keeping track of the objects with collisions so we can report begin and end of a collision
84 private List<BSPrim> m_vehicles = new List<BSPrim>(); 80 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
85 private float[] m_heightMap; 81 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
86 private float m_waterLevel; 82 // Keep track of all the avatars so we can send them a collision event
87 private uint m_worldID; 83 // every tick so OpenSim will update its animation.
88 public uint WorldID { get { return m_worldID; } } 84 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
85
86 // List of all the objects that have vehicle properties and should be called
87 // to update each physics step.
88 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
89 89
90 // let my minuions use my logger 90 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } } 91 public ILog Logger { get { return m_log; } }
92 92
93 private bool m_initialized = false; 93 // If non-zero, the number of simulation steps between calls to the physics
94 94 // engine to output detailed physics stats. Debug logging level must be on also.
95 private int m_detailedStatsStep = 0; 95 private int m_detailedStatsStep = 0;
96 96
97 public IMesher mesher; 97 public IMesher mesher;
98 private float m_meshLOD; 98 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 99 public float MeshLOD { get; private set; }
100 { 100 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 101 public float MeshMegaPrimThreshold { get; private set; }
102 } 102 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 103
109 private BulletSim m_worldSim; 104 public uint WorldID { get; private set; }
110 public BulletSim World 105 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 106
107 // All the constraints that have been allocated in this instance.
108 public BSConstraintCollection Constraints { get; private set; }
109
110 // Simulation parameters
120 private int m_maxSubSteps; 111 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 112 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 113 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 114 public long SimulationStep { get { return m_simulationStep; } }
124 115
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 116 // 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 117 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 118 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 119
120 // True if initialized and ready to do simulation steps
121 private bool m_initialized = false;
131 122
123 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 124 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 125 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 126 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +129,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 129 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 130 private GCHandle m_updateArrayPinnedHandle;
139 131
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 132 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 133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
142 134
143 public float PID_D { get; private set; } // derivative 135 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional 136 public float PID_P { get; private set; } // proportional
145 137
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 138 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 139 public const uint GROUNDPLANE_ID = 1;
140 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
141
142 private float m_waterLevel;
143 public BSTerrainManager TerrainManager { get; private set; }
148 144
149 public ConfigurationParameters Params 145 public ConfigurationParameters Params
150 { 146 {
@@ -154,13 +150,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
154 { 150 {
155 get { return new Vector3(0f, 0f, Params.gravity); } 151 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 152 }
157 153 // Just the Z value of the gravity
158 private float m_maximumObjectMass; 154 public float DefaultGravityZ
159 public float MaximumObjectMass
160 { 155 {
161 get { return m_maximumObjectMass; } 156 get { return Params.gravity; }
162 } 157 }
163 158
159 public float MaximumObjectMass { get; private set; }
160
161 // When functions in the unmanaged code must be called, it is only
162 // done at a known time just before the simulation step. The taint
163 // system saves all these function calls and executes them in
164 // order before the simulation.
164 public delegate void TaintCallback(); 165 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 166 private struct TaintCallbackEntry
166 { 167 {
@@ -172,15 +173,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 callback = c; 173 callback = c;
173 } 174 }
174 } 175 }
176 private Object _taintLock = new Object(); // lock for using the next object
175 private List<TaintCallbackEntry> _taintedObjects; 177 private List<TaintCallbackEntry> _taintedObjects;
176 private Object _taintLock = new Object();
177 178
178 // A pointer to an instance if this structure is passed to the C++ code 179 // A pointer to an instance if this structure is passed to the C++ code
180 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 181 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 182 GCHandle m_paramsHandle;
181 183
182 public bool ShouldDebugLog { get; private set; } 184 // Handle to the callback used by the unmanaged code to call into the managed code.
183 185 // Used for debug logging.
186 // Need to store the handle in a persistant variable so it won't be freed.
184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 187 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
185 188
186 // Sometimes you just have to log everything. 189 // Sometimes you just have to log everything.
@@ -189,17 +192,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private string m_physicsLoggingDir; 192 private string m_physicsLoggingDir;
190 private string m_physicsLoggingPrefix; 193 private string m_physicsLoggingPrefix;
191 private int m_physicsLoggingFileMinutes; 194 private int m_physicsLoggingFileMinutes;
195 // 'true' of the vehicle code is to log lots of details
196 public bool VehicleLoggingEnabled { get; private set; }
192 197
193 private bool m_vehicleLoggingEnabled; 198 #region Construction and Initialization
194 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
195
196 public BSScene(string identifier) 199 public BSScene(string identifier)
197 { 200 {
198 m_initialized = false; 201 m_initialized = false;
202 // we are passed the name of the region we're working for.
203 RegionName = identifier;
199 } 204 }
200 205
201 public override void Initialise(IMesher meshmerizer, IConfigSource config) 206 public override void Initialise(IMesher meshmerizer, IConfigSource config)
202 { 207 {
208 mesher = meshmerizer;
209 _taintedObjects = new List<TaintCallbackEntry>();
210 PhysObjects = new Dictionary<uint, BSPhysObject>();
211 Shapes = new BSShapeCollection(this);
212
203 // Allocate pinned memory to pass parameters. 213 // Allocate pinned memory to pass parameters.
204 m_params = new ConfigurationParameters[1]; 214 m_params = new ConfigurationParameters[1];
205 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 215 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,7 +225,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 225
216 // Enable very detailed logging. 226 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 227 // 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. 228 // can be left in and every call doesn't have to check for null.
219 if (m_physicsLoggingEnabled) 229 if (m_physicsLoggingEnabled)
220 { 230 {
221 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 231 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -225,38 +235,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 235 PhysicsLogging = new Logging.LogWriter();
226 } 236 }
227 237
228 // Get the version of the DLL 238 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 239 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) 240 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 241 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 242 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 243 if (PhysicsLogging.Enabled)
244 // 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); 245 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 246 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 247 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 } 248 }
244 249
245 _taintedObjects = new List<TaintCallbackEntry>(); 250 // Get the version of the DLL
251 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
252 // BulletSimVersion = BulletSimAPI.GetVersion();
253 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 254
247 mesher = meshmerizer; 255 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 256 // a child in a mega-region.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 257 // Turns out that Bullet really doesn't care about the extents of the simulated
258 // area. It tracks active objects no matter where they are.
259 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
250 260
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 261 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 262 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 263 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 264 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
265 m_DebugLogCallbackHandle);
255 266
256 // Initialization to support the transition to a new API which puts most of the logic 267 // 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. 268 // 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)); 269 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
259 m_constraintCollection = new BSConstraintCollection(World); 270
271 Constraints = new BSConstraintCollection(World);
272
273 TerrainManager = new BSTerrainManager(this);
274 TerrainManager.CreateInitialGroundPlaneAndTerrain();
260 275
261 m_initialized = true; 276 m_initialized = true;
262 } 277 }
@@ -281,10 +296,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 296 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 297 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 298 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 299 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 300 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 301 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 302 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
303
304 // Do any replacements in the parameters
305 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 306 }
289 } 307 }
290 } 308 }
@@ -309,13 +327,51 @@ public class BSScene : PhysicsScene, IPhysicsParameters
309 { 327 {
310 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 328 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
311 } 329 }
312 330
313 // Called directly from unmanaged code so don't do much 331 // Called directly from unmanaged code so don't do much
314 private void BulletLoggerPhysLog(string msg) 332 private void BulletLoggerPhysLog(string msg)
315 { 333 {
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 334 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
317 } 335 }
318 336
337 public override void Dispose()
338 {
339 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
340
341 // make sure no stepping happens while we're deleting stuff
342 m_initialized = false;
343
344 TerrainManager.ReleaseGroundPlaneAndTerrain();
345
346 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
347 {
348 kvp.Value.Destroy();
349 }
350 PhysObjects.Clear();
351
352 // Now that the prims are all cleaned up, there should be no constraints left
353 if (Constraints != null)
354 {
355 Constraints.Dispose();
356 Constraints = null;
357 }
358
359 if (Shapes != null)
360 {
361 Shapes.Dispose();
362 Shapes = null;
363 }
364
365 // Anything left in the unmanaged code should be cleaned out
366 BulletSimAPI.Shutdown(WorldID);
367
368 // Not logging any more
369 PhysicsLogging.Close();
370 }
371 #endregion // Construction and Initialization
372
373 #region Prim and Avatar addition and removal
374
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 375 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 376 {
321 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 377 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -329,7 +385,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 385 if (!m_initialized) return null;
330 386
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 387 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 388 lock (PhysObjects) PhysObjects.Add(localID, actor);
389
390 // TODO: Remove kludge someday.
391 // We must generate a collision for avatars whether they collide or not.
392 // This is required by OpenSim to update avatar animations, etc.
393 lock (m_avatars) m_avatars.Add(actor);
394
333 return actor; 395 return actor;
334 } 396 }
335 397
@@ -344,7 +406,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 406 {
345 try 407 try
346 { 408 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 409 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
410 // Remove kludge someday
411 lock (m_avatars) m_avatars.Remove(bsactor);
348 } 412 }
349 catch (Exception e) 413 catch (Exception e)
350 { 414 {
@@ -362,11 +426,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 426 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 427 if (bsprim != null)
364 { 428 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 429 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 430 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 431 try
368 { 432 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 433 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 434 }
371 catch (Exception e) 435 catch (Exception e)
372 { 436 {
@@ -388,18 +452,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 452
389 if (!m_initialized) return null; 453 if (!m_initialized) return null;
390 454
391 // DetailLog("{0},AddPrimShape,call", localID); 455 DetailLog("{0},AddPrimShape,call", localID);
392 456
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 457 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 458 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 459 return prim;
396 } 460 }
397 461
398 // This is a call from the simulator saying that some physical property has been updated. 462 // 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 463 // The BulletSim driver senses the changing of relevant properties so this taint
400 // information call is not needed. 464 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 465 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 466
467 #endregion // Prim and Avatar addition and removal
468
469 #region Simulation
403 // Simulate one timestep 470 // Simulate one timestep
404 public override float Simulate(float timeStep) 471 public override float Simulate(float timeStep)
405 { 472 {
@@ -408,18 +475,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 475 int collidersCount = 0;
409 IntPtr collidersPtr; 476 IntPtr collidersPtr;
410 477
411 LastSimulatedTimestep = timeStep; 478 int beforeTime = 0;
479 int simTime = 0;
412 480
413 // prevent simulation until we've been initialized 481 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 482 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 483
418 // update the prim states while we know the physics engine is not busy 484 // update the prim states while we know the physics engine is not busy
485 int numTaints = _taintedObjects.Count;
419 ProcessTaints(); 486 ProcessTaints();
420 487
421 // Some of the prims operate with special vehicle properties 488 // Some of the prims operate with special vehicle properties
422 ProcessVehicles(timeStep); 489 ProcessVehicles(timeStep);
490 numTaints += _taintedObjects.Count;
423 ProcessTaints(); // the vehicles might have added taints 491 ProcessTaints(); // the vehicles might have added taints
424 492
425 // step the physical world one interval 493 // step the physical world one interval
@@ -427,15 +495,22 @@ public class BSScene : PhysicsScene, IPhysicsParameters
427 int numSubSteps = 0; 495 int numSubSteps = 0;
428 try 496 try
429 { 497 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 498 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
499
500 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 501 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 502
503 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
504 DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
505 DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
433 } 506 }
434 catch (Exception e) 507 catch (Exception e)
435 { 508 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 509 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); 510 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 511 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
512 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
513 updatedEntityCount = 0;
439 collidersCount = 0; 514 collidersCount = 0;
440 } 515 }
441 516
@@ -443,7 +518,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 518 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 519
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 520 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 521 SimulationNowTime = Util.EnvironmentTickCount();
447 522
448 // If there were collisions, process them by sending the event to the prim. 523 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 524 // Collisions must be processed before updates.
@@ -460,21 +535,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
460 } 535 }
461 } 536 }
462 537
538 // This is a kludge to get avatar movement updates.
539 // ODE sends collisions for avatars even if there are have been no collisions. This updates
540 // avatar animations and stuff.
541 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
542 foreach (BSPhysObject bsp in m_avatars)
543 bsp.SendCollisions();
544
463 // The above SendCollision's batch up the collisions on the objects. 545 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 546 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 547 if (ObjectsWithCollisions.Count > 0)
466 bsp.SendCollisions(); 548 {
467 m_primsWithCollisions.Clear(); 549 foreach (BSPhysObject bsp in ObjectsWithCollisions)
550 if (!m_avatars.Contains(bsp)) // don't call avatars twice
551 if (!bsp.SendCollisions())
552 {
553 // If the object is done colliding, see that it's removed from the colliding list
554 ObjectsWithNoMoreCollisions.Add(bsp);
555 }
556 }
468 557
469 // This is a kludge to get avatar movement updated. 558 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
470 // Don't send collisions only if there were collisions -- send everytime. 559 // This can't be done by SendCollisions because it is inside an iteration of ObjectWithCollisions.
471 // ODE sends collisions even if there are none and this is used to update 560 if (ObjectsWithNoMoreCollisions.Count > 0)
472 // avatar animations and stuff. 561 {
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 562 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
474 // bsc.SendCollisions(); 563 ObjectsWithCollisions.Remove(po);
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 564 ObjectsWithNoMoreCollisions.Clear();
476 kvp.Value.SendCollisions(); 565 }
477 m_avatarsWithCollisions.Clear();
478 566
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 567 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 568 if (updatedEntityCount > 0)
@@ -482,17 +570,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 570 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 571 {
484 EntityProperties entprop = m_updateArray[ii]; 572 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 573 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 574 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
487 { 575 {
488 prim.UpdateProperties(entprop); 576 pobj.UpdateProperties(entprop);
489 continue;
490 }
491 BSCharacter actor;
492 if (m_avatars.TryGetValue(entprop.ID, out actor))
493 {
494 actor.UpdateProperties(entprop);
495 continue;
496 } 577 }
497 } 578 }
498 } 579 }
@@ -506,121 +587,89 @@ public class BSScene : PhysicsScene, IPhysicsParameters
506 } 587 }
507 } 588 }
508 589
509 // this is a waste since the outside routine also calcuates the physics simulation 590 // 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. 591 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); 592 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
512 // return (timeStep * (float)simulateTotalTime); 593 return numSubSteps * m_fixedTimeStep * 1000;
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 } 594 }
522 595
523 // Something has collided 596 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 597 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 598 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 599 if (localID <= TerrainManager.HighestTerrainID)
527 { 600 {
528 return; // don't send collisions to the terrain 601 return; // don't send collisions to the terrain
529 } 602 }
530 603
531 ActorTypes type = ActorTypes.Prim; 604 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 605 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 606 {
534 else if (m_avatars.ContainsKey(collidingWith)) 607 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent; 608 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; 609 return;
542 } 610 }
543 BSCharacter actor; 611
544 if (m_avatars.TryGetValue(localID, out actor)) { 612 // 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); 613 BSPhysObject collidee = null;
546 m_avatarsWithCollisions.Add(actor); 614 PhysObjects.TryGetValue(collidingWith, out collidee);
547 return; 615
616 DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
617
618 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
619 {
620 // If a collision was posted, remember to send it to the simulator
621 ObjectsWithCollisions.Add(collider);
548 } 622 }
623
549 return; 624 return;
550 } 625 }
551 626
552 public override void GetResults() { } 627 #endregion // Simulation
553 628
554 public override void SetTerrain(float[] heightMap) { 629 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 630
562 // Someday we will have complex terrain with caves and tunnels 631 #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 632
569 public float GetTerrainHeightAtXY(float tX, float tY) 633 public override void SetTerrain(float[] heightMap) {
570 { 634 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 } 635 }
575 636
576 public override void SetWaterLevel(float baseheight) 637 public override void SetWaterLevel(float baseheight)
577 { 638 {
578 m_waterLevel = baseheight; 639 m_waterLevel = baseheight;
579 // TODO: pass to physics engine so things will float?
580 } 640 }
581 public float GetWaterLevel() 641 // Someday....
642 public float GetWaterLevelAtXYZ(Vector3 loc)
582 { 643 {
583 return m_waterLevel; 644 return m_waterLevel;
584 } 645 }
585 646
586 public override void DeleteTerrain() 647 public override void DeleteTerrain()
587 { 648 {
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 649 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
589 } 650 }
590 651
591 public override void Dispose() 652 // Although no one seems to check this, I do support combining.
653 public override bool SupportsCombining()
592 { 654 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 655 return TerrainManager.SupportsCombining();
594 656 }
595 // make sure no stepping happens while we're deleting stuff 657 // This call says I am a child to region zero in a mega-region. 'pScene' is that
596 m_initialized = false; 658 // of region zero, 'offset' is my offset from regions zero's origin, and
597 659 // 'extents' is the largest XY that is handled in my region.
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 660 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
599 { 661 {
600 kvp.Value.Destroy(); 662 TerrainManager.Combine(pScene, offset, extents);
601 } 663 }
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 664
620 // Not logging any more 665 // Unhook all the combining that I know about.
621 PhysicsLogging.Close(); 666 public override void UnCombine(PhysicsScene pScene)
667 {
668 TerrainManager.UnCombine(pScene);
622 } 669 }
623 670
671 #endregion // Terrain
672
624 public override Dictionary<uint, float> GetTopColliders() 673 public override Dictionary<uint, float> GetTopColliders()
625 { 674 {
626 return new Dictionary<uint, float>(); 675 return new Dictionary<uint, float>();
@@ -628,121 +677,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
628 677
629 public override bool IsThreaded { get { return false; } } 678 public override bool IsThreaded { get { return false; } }
630 679
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 680 // 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. 681 // 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. 682 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -751,7 +685,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
751 if (!m_initialized) return; 685 if (!m_initialized) return;
752 686
753 lock (_taintLock) 687 lock (_taintLock)
688 {
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 689 _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
690 }
691
755 return; 692 return;
756 } 693 }
757 694
@@ -830,14 +767,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
830 // no locking because only called when physics engine is not busy 767 // no locking because only called when physics engine is not busy
831 private void ProcessVehicles(float timeStep) 768 private void ProcessVehicles(float timeStep)
832 { 769 {
833 foreach (BSPrim prim in m_vehicles) 770 foreach (BSPhysObject pobj in m_vehicles)
834 { 771 {
835 prim.StepVehicle(timeStep); 772 pobj.StepVehicle(timeStep);
836 } 773 }
837 } 774 }
838 #endregion Vehicles 775 #endregion Vehicles
839 776
840 #region Parameters 777 #region INI and command line parameter processing
841 778
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 779 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 780 delegate float ParamGet(BSScene scene);
@@ -869,7 +806,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
869 // getters and setters. 806 // getters and setters.
870 // It is easiest to find an existing definition and copy it. 807 // It is easiest to find an existing definition and copy it.
871 // Parameter values are floats. Booleans are converted to a floating value. 808 // Parameter values are floats. Booleans are converted to a floating value.
872 // 809 //
873 // A ParameterDefn() takes the following parameters: 810 // A ParameterDefn() takes the following parameters:
874 // -- the text name of the parameter. This is used for console input and ini file. 811 // -- 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. 812 // -- a short text description of the parameter. This shows up in the console listing.
@@ -888,25 +825,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 825 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 826 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 827 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 828 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 829 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 830 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 831 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 832 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 833 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 834 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 835 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
899 836
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 837 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 838 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 839 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 840 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 841 (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)", 842 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
843 16f,
844 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
845 (s) => { return s.MeshMegaPrimLOD; },
846 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
847 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
848 10f,
849 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
850 (s) => { return s.MeshMegaPrimThreshold; },
851 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
852 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 853 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 854 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 855 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 856 (s,p,l,v) => { s.SculptLOD = v; } ),
910 857
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 858 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 859 10f,
@@ -930,9 +877,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 877 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 878 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 879 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 880 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 881 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 882 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 883
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 884 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 885 2200f,
@@ -976,42 +923,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
976 0f, 923 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 924 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 925 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 926 (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)", 927 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 928 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 929 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 930 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 931 (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", 932 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 933 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 934 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 935 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 936 (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", 937 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 938 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 939 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 940 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 941 (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", 942 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 943 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 944 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 945 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 946 (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)" , 947 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 948 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 949 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 950 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 951 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 952 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 953 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 954 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 955 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 956 (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" , 957 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 958 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 959 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 960 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 961 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
1015 962
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 963 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 964 0.5f,
@@ -1029,35 +976,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1029 (s) => { return s.m_params[0].terrainRestitution; }, 976 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 977 (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.", 978 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 979 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 980 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 981 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 982 (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.", 983 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 984 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 985 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 986 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 987 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 988 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 989 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 990 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 991 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 992 (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", 993 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1047 0.37f, 994 0.37f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 995 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 996 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 997 (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", 998 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 999 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1000 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 1001 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 1002 (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", 1003 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 1004 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 1005 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1006 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1007 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 1008
1062 1009
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1010 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
@@ -1086,7 +1033,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1086 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, 1033 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1087 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1034 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1088 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1035 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1089 ConfigurationParameters.numericFalse, 1036 ConfigurationParameters.numericTrue,
1090 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1037 (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; }, 1038 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1092 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1039 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1121,8 +1068,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1068 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1069 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1070 (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", 1071 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1072 0.1f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1073 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1074 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1075 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
@@ -1131,18 +1078,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1078 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1079 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1080 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1081 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1082 40,
1083 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1084 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1085 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1086
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1087 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1088 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1089 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1090 (s) => { return (float)s.m_detailedStatsStep; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1091 (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 }; 1092 };
1147 1093
1148 // Convert a boolean to our numeric true and false values 1094 // Convert a boolean to our numeric true and false values
@@ -1200,6 +1146,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1146
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1147 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1148
1149 // This creates an array in the correct format for returning the list of
1150 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1151 private void BuildParameterTable()
1204 { 1152 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1153 if (SettableParameters.Length < ParameterDefinitions.Length)
@@ -1250,18 +1198,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1250 } 1198 }
1251 1199
1252 // check to see if we are updating a parameter for a particular or all of the prims 1200 // 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) 1201 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 { 1202 {
1263 List<uint> operateOn; 1203 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1204 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val); 1205 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 } 1206 }
1267 1207
@@ -1284,11 +1224,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1224 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs) 1225 foreach (uint lID in objectIDs)
1286 { 1226 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); 1227 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1288 } 1228 }
1289 }); 1229 });
1290 break; 1230 break;
1291 default: 1231 default:
1292 // setting only one localID 1232 // setting only one localID
1293 TaintedUpdateParameter(parm, localID, val); 1233 TaintedUpdateParameter(parm, localID, val);
1294 break; 1234 break;
@@ -1302,7 +1242,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1302 string xparm = parm.ToLower(); 1242 string xparm = parm.ToLower();
1303 float xval = val; 1243 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1244 TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1245 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
1306 }); 1246 });
1307 } 1247 }
1308 1248