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