diff options
author | teravus | 2012-11-15 10:05:16 -0500 |
---|---|---|
committer | teravus | 2012-11-15 10:05:16 -0500 |
commit | e9153e1d1aae50024d8cd05fe14a9bce34343a0e (patch) | |
tree | bc111d34f95a26b99c7e34d9e495dc14d1802cc3 /OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |
parent | Merge master into teravuswork (diff) | |
download | opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.zip opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.tar.gz opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.tar.bz2 opensim-SC-e9153e1d1aae50024d8cd05fe14a9bce34343a0e.tar.xz |
Revert "Merge master into teravuswork", it should have been avination, not master.
This reverts commit dfac269032300872c4d0dc507f4f9062d102b0f4, reversing
changes made to 619c39e5144f15aca129d6d999bcc5c34133ee64.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 978 |
1 files changed, 417 insertions, 561 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 740f339..a31c578 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,88 +39,96 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Test sculpties (verified that they don't work) | 42 | // Debug linkset |
43 | // Test with multiple regions in one simulator | ||
44 | // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) | ||
45 | // Test sculpties | ||
43 | // Compute physics FPS reasonably | 46 | // Compute physics FPS reasonably |
44 | // Based on material, set density and friction | 47 | // Based on material, set density and friction |
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | 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. | ||
46 | // 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? |
47 | // 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) |
48 | // 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 |
49 | // 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 | ||
50 | // Check out llVolumeDetect. Must do something for that. | 55 | // Check out llVolumeDetect. Must do something for that. |
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
53 | // 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? |
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | 57 | // changing the position and orientation of a linked prim must rebuild the constraint with the root. |
58 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once | ||
55 | // 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 |
60 | // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) | ||
56 | // Implement LockAngularMotion | 61 | // Implement LockAngularMotion |
57 | // 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) |
63 | // Does NeedsMeshing() really need to exclude all the different shapes? | ||
58 | // 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. |
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | 65 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? |
60 | // Check terrain size. 128 or 127? | 66 | // Check terrain size. 128 or 127? |
61 | // Raycast | 67 | // Raycast |
62 | // | 68 | // |
63 | namespace OpenSim.Region.Physics.BulletSPlugin | 69 | namespace OpenSim.Region.Physics.BulletSPlugin |
64 | { | 70 | { |
65 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | 71 | public class BSScene : PhysicsScene, IPhysicsParameters |
66 | { | 72 | { |
67 | 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); |
68 | private static readonly string LogHeader = "[BULLETS SCENE]"; | 74 | private static readonly string LogHeader = "[BULLETS SCENE]"; |
69 | 75 | ||
70 | // The name of the region we're working for. | 76 | public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } |
71 | public string RegionName { get; private set; } | ||
72 | 77 | ||
73 | public string BulletSimVersion = "?"; | 78 | public string BulletSimVersion = "?"; |
74 | 79 | ||
75 | public Dictionary<uint, BSPhysObject> PhysObjects; | 80 | private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); |
76 | public BSShapeCollection Shapes; | 81 | private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); |
77 | 82 | private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); | |
78 | // Keeping track of the objects with collisions so we can report begin and end of a collision | 83 | private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>(); |
79 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | 84 | private List<BSPrim> m_vehicles = new List<BSPrim>(); |
80 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | 85 | private float[] m_heightMap; |
81 | // Keep track of all the avatars so we can send them a collision event | 86 | private float m_waterLevel; |
82 | // every tick so OpenSim will update its animation. | 87 | private uint m_worldID; |
83 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 88 | public uint WorldID { get { return m_worldID; } } |
84 | |||
85 | // List of all the objects that have vehicle properties and should be called | ||
86 | // to update each physics step. | ||
87 | private List<BSPhysObject> m_vehicles = new List<BSPhysObject>(); | ||
88 | 89 | ||
89 | // let my minuions use my logger | 90 | // let my minuions use my logger |
90 | public ILog Logger { get { return m_log; } } | 91 | public ILog Logger { get { return m_log; } } |
91 | 92 | ||
92 | public IMesher mesher; | 93 | private bool m_initialized = false; |
93 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
94 | public float MeshLOD { get; private set; } | ||
95 | public float MeshMegaPrimLOD { get; private set; } | ||
96 | public float MeshMegaPrimThreshold { get; private set; } | ||
97 | public float SculptLOD { get; private set; } | ||
98 | 94 | ||
99 | public uint WorldID { get; private set; } | 95 | private int m_detailedStatsStep = 0; |
100 | public BulletSim World { get; private set; } | 96 | |
97 | public IMesher mesher; | ||
98 | private float m_meshLOD; | ||
99 | public float MeshLOD | ||
100 | { | ||
101 | get { return m_meshLOD; } | ||
102 | } | ||
103 | private float m_sculptLOD; | ||
104 | public float SculptLOD | ||
105 | { | ||
106 | get { return m_sculptLOD; } | ||
107 | } | ||
101 | 108 | ||
102 | // All the constraints that have been allocated in this instance. | 109 | private BulletSim m_worldSim; |
103 | public BSConstraintCollection Constraints { get; private set; } | 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 | } | ||
104 | 119 | ||
105 | // Simulation parameters | ||
106 | private int m_maxSubSteps; | 120 | private int m_maxSubSteps; |
107 | private float m_fixedTimeStep; | 121 | private float m_fixedTimeStep; |
108 | private long m_simulationStep = 0; | 122 | private long m_simulationStep = 0; |
109 | public long SimulationStep { get { return m_simulationStep; } } | 123 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | 124 | |
125 | public float LastSimulatedTimestep { get; private set; } | ||
111 | 126 | ||
112 | // 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 |
113 | // 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 |
114 | public int SimulationNowTime { get; private set; } | 129 | private int m_simulationNowTime; |
115 | 130 | public int SimulationNowTime { get { return m_simulationNowTime; } } | |
116 | // True if initialized and ready to do simulation steps | ||
117 | private bool m_initialized = false; | ||
118 | |||
119 | // Flag which is true when processing taints. | ||
120 | // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. | ||
121 | public bool InTaintTime { get; private set; } | ||
122 | 131 | ||
123 | // Pinned memory used to pass step information between managed and unmanaged | ||
124 | private int m_maxCollisionsPerFrame; | 132 | private int m_maxCollisionsPerFrame; |
125 | private CollisionDesc[] m_collisionArray; | 133 | private CollisionDesc[] m_collisionArray; |
126 | private GCHandle m_collisionArrayPinnedHandle; | 134 | private GCHandle m_collisionArrayPinnedHandle; |
@@ -129,19 +137,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
129 | private EntityProperties[] m_updateArray; | 137 | private EntityProperties[] m_updateArray; |
130 | private GCHandle m_updateArrayPinnedHandle; | 138 | private GCHandle m_updateArrayPinnedHandle; |
131 | 139 | ||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | 140 | private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed |
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // 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 |
134 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
135 | 142 | ||
136 | public float PID_D { get; private set; } // derivative | 143 | public float PID_D { get; private set; } // derivative |
137 | public float PID_P { get; private set; } // proportional | 144 | public float PID_P { get; private set; } // proportional |
138 | 145 | ||
139 | 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 |
140 | public const uint GROUNDPLANE_ID = 1; | 147 | public const uint GROUNDPLANE_ID = 1; |
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | ||
142 | |||
143 | private float m_waterLevel; | ||
144 | public BSTerrainManager TerrainManager { get; private set; } | ||
145 | 148 | ||
146 | public ConfigurationParameters Params | 149 | public ConfigurationParameters Params |
147 | { | 150 | { |
@@ -151,18 +154,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
151 | { | 154 | { |
152 | get { return new Vector3(0f, 0f, Params.gravity); } | 155 | get { return new Vector3(0f, 0f, Params.gravity); } |
153 | } | 156 | } |
154 | // Just the Z value of the gravity | 157 | |
155 | public float DefaultGravityZ | 158 | private float m_maximumObjectMass; |
159 | public float MaximumObjectMass | ||
156 | { | 160 | { |
157 | get { return Params.gravity; } | 161 | get { return m_maximumObjectMass; } |
158 | } | 162 | } |
159 | 163 | ||
160 | public float MaximumObjectMass { get; private set; } | ||
161 | |||
162 | // When functions in the unmanaged code must be called, it is only | ||
163 | // done at a known time just before the simulation step. The taint | ||
164 | // system saves all these function calls and executes them in | ||
165 | // order before the simulation. | ||
166 | public delegate void TaintCallback(); | 164 | public delegate void TaintCallback(); |
167 | private struct TaintCallbackEntry | 165 | private struct TaintCallbackEntry |
168 | { | 166 | { |
@@ -174,19 +172,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
174 | callback = c; | 172 | callback = c; |
175 | } | 173 | } |
176 | } | 174 | } |
177 | private Object _taintLock = new Object(); // lock for using the next object | 175 | private List<TaintCallbackEntry> _taintedObjects; |
178 | private List<TaintCallbackEntry> _taintOperations; | 176 | private Object _taintLock = new Object(); |
179 | private Dictionary<string, TaintCallbackEntry> _postTaintOperations; | ||
180 | private List<TaintCallbackEntry> _postStepOperations; | ||
181 | 177 | ||
182 | // A pointer to an instance if this structure is passed to the C++ code | 178 | // A pointer to an instance if this structure is passed to the C++ code |
183 | // Used to pass basic configuration values to the unmanaged code. | ||
184 | ConfigurationParameters[] m_params; | 179 | ConfigurationParameters[] m_params; |
185 | GCHandle m_paramsHandle; | 180 | GCHandle m_paramsHandle; |
186 | 181 | ||
187 | // Handle to the callback used by the unmanaged code to call into the managed code. | 182 | public bool ShouldDebugLog { get; private set; } |
188 | // Used for debug logging. | 183 | |
189 | // Need to store the handle in a persistant variable so it won't be freed. | ||
190 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | 184 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; |
191 | 185 | ||
192 | // Sometimes you just have to log everything. | 186 | // Sometimes you just have to log everything. |
@@ -195,26 +189,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 189 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 190 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 191 | private int m_physicsLoggingFileMinutes; |
198 | // 'true' of the vehicle code is to log lots of details | ||
199 | public bool VehicleLoggingEnabled { get; private set; } | ||
200 | 192 | ||
201 | #region Construction and Initialization | 193 | private bool m_vehicleLoggingEnabled; |
194 | public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } } | ||
195 | |||
202 | public BSScene(string identifier) | 196 | public BSScene(string identifier) |
203 | { | 197 | { |
204 | m_initialized = false; | 198 | m_initialized = false; |
205 | // we are passed the name of the region we're working for. | ||
206 | RegionName = identifier; | ||
207 | } | 199 | } |
208 | 200 | ||
209 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | 201 | public override void Initialise(IMesher meshmerizer, IConfigSource config) |
210 | { | 202 | { |
211 | mesher = meshmerizer; | ||
212 | _taintOperations = new List<TaintCallbackEntry>(); | ||
213 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
214 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
215 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | ||
216 | Shapes = new BSShapeCollection(this); | ||
217 | |||
218 | // Allocate pinned memory to pass parameters. | 203 | // Allocate pinned memory to pass parameters. |
219 | m_params = new ConfigurationParameters[1]; | 204 | m_params = new ConfigurationParameters[1]; |
220 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); | 205 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); |
@@ -230,7 +215,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
230 | 215 | ||
231 | // Enable very detailed logging. | 216 | // Enable very detailed logging. |
232 | // By creating an empty logger when not logging, the log message invocation code | 217 | // By creating an empty logger when not logging, the log message invocation code |
233 | // can be left in and every call doesn't have to check for null. | 218 | // can be left in and every call doesn't have to check for null. |
234 | if (m_physicsLoggingEnabled) | 219 | if (m_physicsLoggingEnabled) |
235 | { | 220 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 221 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
@@ -240,43 +225,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
240 | PhysicsLogging = new Logging.LogWriter(); | 225 | PhysicsLogging = new Logging.LogWriter(); |
241 | } | 226 | } |
242 | 227 | ||
243 | // If Debug logging level, enable logging from the unmanaged code | 228 | // Get the version of the DLL |
244 | m_DebugLogCallbackHandle = null; | 229 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. |
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 | ||
245 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) | 234 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) |
246 | { | 235 | { |
247 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | 236 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); |
248 | if (PhysicsLogging.Enabled) | 237 | if (PhysicsLogging.Enabled) |
249 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
250 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); | 238 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); |
251 | else | 239 | else |
252 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | 240 | 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); | ||
253 | } | 243 | } |
254 | 244 | ||
255 | // Get the version of the DLL | 245 | _taintedObjects = new List<TaintCallbackEntry>(); |
256 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
257 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
258 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
259 | 246 | ||
260 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 247 | mesher = meshmerizer; |
261 | // a child in a mega-region. | 248 | // The bounding box for the simulated world |
262 | // Bullet actually doesn't care about the extents of the simulated | 249 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); |
263 | // area. It tracks active objects no matter where they are. | ||
264 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
265 | 250 | ||
266 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 251 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); |
267 | World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | 252 | m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), |
268 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | 253 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), |
269 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | 254 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); |
270 | m_DebugLogCallbackHandle)); | ||
271 | |||
272 | Constraints = new BSConstraintCollection(World); | ||
273 | 255 | ||
274 | TerrainManager = new BSTerrainManager(this); | 256 | // Initialization to support the transition to a new API which puts most of the logic |
275 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 257 | // 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)); | ||
259 | m_constraintCollection = new BSConstraintCollection(World); | ||
276 | 260 | ||
277 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); | ||
278 | |||
279 | InTaintTime = false; | ||
280 | m_initialized = true; | 261 | m_initialized = true; |
281 | } | 262 | } |
282 | 263 | ||
@@ -300,13 +281,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
300 | // Very detailed logging for physics debugging | 281 | // Very detailed logging for physics debugging |
301 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | 282 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 283 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 284 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 285 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
305 | // Very detailed logging for vehicle debugging | 286 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 287 | m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
307 | |||
308 | // Do any replacements in the parameters | ||
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | ||
310 | } | 288 | } |
311 | } | 289 | } |
312 | } | 290 | } |
@@ -331,50 +309,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
331 | { | 309 | { |
332 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | 310 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); |
333 | } | 311 | } |
334 | 312 | ||
335 | // Called directly from unmanaged code so don't do much | 313 | // Called directly from unmanaged code so don't do much |
336 | private void BulletLoggerPhysLog(string msg) | 314 | private void BulletLoggerPhysLog(string msg) |
337 | { | 315 | { |
338 | DetailLog("[BULLETS UNMANAGED]:" + msg); | 316 | PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); |
339 | } | ||
340 | |||
341 | public override void Dispose() | ||
342 | { | ||
343 | // m_log.DebugFormat("{0}: Dispose()", LogHeader); | ||
344 | |||
345 | // make sure no stepping happens while we're deleting stuff | ||
346 | m_initialized = false; | ||
347 | |||
348 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
349 | |||
350 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
351 | { | ||
352 | kvp.Value.Destroy(); | ||
353 | } | ||
354 | PhysObjects.Clear(); | ||
355 | |||
356 | // Now that the prims are all cleaned up, there should be no constraints left | ||
357 | if (Constraints != null) | ||
358 | { | ||
359 | Constraints.Dispose(); | ||
360 | Constraints = null; | ||
361 | } | ||
362 | |||
363 | if (Shapes != null) | ||
364 | { | ||
365 | Shapes.Dispose(); | ||
366 | Shapes = null; | ||
367 | } | ||
368 | |||
369 | // Anything left in the unmanaged code should be cleaned out | ||
370 | BulletSimAPI.Shutdown2(World.ptr); | ||
371 | |||
372 | // Not logging any more | ||
373 | PhysicsLogging.Close(); | ||
374 | } | 317 | } |
375 | #endregion // Construction and Initialization | ||
376 | |||
377 | #region Prim and Avatar addition and removal | ||
378 | 318 | ||
379 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) | 319 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) |
380 | { | 320 | { |
@@ -389,13 +329,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
389 | if (!m_initialized) return null; | 329 | if (!m_initialized) return null; |
390 | 330 | ||
391 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); | 331 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); |
392 | lock (PhysObjects) PhysObjects.Add(localID, actor); | 332 | lock (m_avatars) m_avatars.Add(localID, actor); |
393 | |||
394 | // TODO: Remove kludge someday. | ||
395 | // We must generate a collision for avatars whether they collide or not. | ||
396 | // This is required by OpenSim to update avatar animations, etc. | ||
397 | lock (m_avatars) m_avatars.Add(actor); | ||
398 | |||
399 | return actor; | 333 | return actor; |
400 | } | 334 | } |
401 | 335 | ||
@@ -410,9 +344,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
410 | { | 344 | { |
411 | try | 345 | try |
412 | { | 346 | { |
413 | lock (PhysObjects) PhysObjects.Remove(actor.LocalID); | 347 | lock (m_avatars) m_avatars.Remove(actor.LocalID); |
414 | // Remove kludge someday | ||
415 | lock (m_avatars) m_avatars.Remove(bsactor); | ||
416 | } | 348 | } |
417 | catch (Exception e) | 349 | catch (Exception e) |
418 | { | 350 | { |
@@ -430,11 +362,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
430 | BSPrim bsprim = prim as BSPrim; | 362 | BSPrim bsprim = prim as BSPrim; |
431 | if (bsprim != null) | 363 | if (bsprim != null) |
432 | { | 364 | { |
433 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); | 365 | // DetailLog("{0},RemovePrim,call", bsprim.LocalID); |
434 | // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); | 366 | // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); |
435 | try | 367 | try |
436 | { | 368 | { |
437 | lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); | 369 | lock (m_prims) m_prims.Remove(bsprim.LocalID); |
438 | } | 370 | } |
439 | catch (Exception e) | 371 | catch (Exception e) |
440 | { | 372 | { |
@@ -456,21 +388,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
456 | 388 | ||
457 | if (!m_initialized) return null; | 389 | if (!m_initialized) return null; |
458 | 390 | ||
459 | DetailLog("{0},AddPrimShape,call", localID); | 391 | // DetailLog("{0},AddPrimShape,call", localID); |
460 | 392 | ||
461 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); | 393 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); |
462 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 394 | lock (m_prims) m_prims.Add(localID, prim); |
463 | return prim; | 395 | return prim; |
464 | } | 396 | } |
465 | 397 | ||
466 | // This is a call from the simulator saying that some physical property has been updated. | 398 | // This is a call from the simulator saying that some physical property has been updated. |
467 | // The BulletSim driver senses the changing of relevant properties so this taint | 399 | // The BulletSim driver senses the changing of relevant properties so this taint |
468 | // information call is not needed. | 400 | // information call is not needed. |
469 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } | 401 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } |
470 | 402 | ||
471 | #endregion // Prim and Avatar addition and removal | ||
472 | |||
473 | #region Simulation | ||
474 | // Simulate one timestep | 403 | // Simulate one timestep |
475 | public override float Simulate(float timeStep) | 404 | public override float Simulate(float timeStep) |
476 | { | 405 | { |
@@ -479,45 +408,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
479 | int collidersCount = 0; | 408 | int collidersCount = 0; |
480 | IntPtr collidersPtr; | 409 | IntPtr collidersPtr; |
481 | 410 | ||
482 | int beforeTime = 0; | 411 | LastSimulatedTimestep = timeStep; |
483 | int simTime = 0; | ||
484 | 412 | ||
485 | // prevent simulation until we've been initialized | 413 | // prevent simulation until we've been initialized |
486 | if (!m_initialized) return 5.0f; | 414 | if (!m_initialized) return 10.0f; |
415 | |||
416 | int simulateStartTime = Util.EnvironmentTickCount(); | ||
487 | 417 | ||
488 | // update the prim states while we know the physics engine is not busy | 418 | // update the prim states while we know the physics engine is not busy |
489 | int numTaints = _taintOperations.Count; | ||
490 | ProcessTaints(); | 419 | ProcessTaints(); |
491 | 420 | ||
492 | // Some of the prims operate with special vehicle properties | 421 | // Some of the prims operate with special vehicle properties |
493 | ProcessVehicles(timeStep); | 422 | ProcessVehicles(timeStep); |
494 | numTaints += _taintOperations.Count; | ||
495 | ProcessTaints(); // the vehicles might have added taints | 423 | ProcessTaints(); // the vehicles might have added taints |
496 | 424 | ||
497 | // step the physical world one interval | 425 | // step the physical world one interval |
498 | m_simulationStep++; | 426 | m_simulationStep++; |
499 | int numSubSteps = 0; | 427 | int numSubSteps = 0; |
500 | |||
501 | try | 428 | try |
502 | { | 429 | { |
503 | // DumpVehicles(); // DEBUG | 430 | numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, |
504 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | ||
505 | |||
506 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | ||
507 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | 431 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); |
508 | 432 | // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); | |
509 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
510 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | ||
511 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | ||
512 | // DumpVehicles(); // DEBUG | ||
513 | } | 433 | } |
514 | catch (Exception e) | 434 | catch (Exception e) |
515 | { | 435 | { |
516 | m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", | 436 | m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); |
517 | LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); | 437 | // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); |
518 | DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", | 438 | // updatedEntityCount = 0; |
519 | DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); | ||
520 | updatedEntityCount = 0; | ||
521 | collidersCount = 0; | 439 | collidersCount = 0; |
522 | } | 440 | } |
523 | 441 | ||
@@ -525,7 +443,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
525 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 443 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in |
526 | 444 | ||
527 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 445 | // Get a value for 'now' so all the collision and update routines don't have to get their own |
528 | SimulationNowTime = Util.EnvironmentTickCount(); | 446 | m_simulationNowTime = Util.EnvironmentTickCount(); |
529 | 447 | ||
530 | // If there were collisions, process them by sending the event to the prim. | 448 | // If there were collisions, process them by sending the event to the prim. |
531 | // Collisions must be processed before updates. | 449 | // Collisions must be processed before updates. |
@@ -544,32 +462,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
544 | 462 | ||
545 | // The above SendCollision's batch up the collisions on the objects. | 463 | // The above SendCollision's batch up the collisions on the objects. |
546 | // Now push the collisions into the simulator. | 464 | // Now push the collisions into the simulator. |
547 | if (ObjectsWithCollisions.Count > 0) | 465 | foreach (BSPrim bsp in m_primsWithCollisions) |
548 | { | 466 | bsp.SendCollisions(); |
549 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | 467 | m_primsWithCollisions.Clear(); |
550 | if (!bsp.SendCollisions()) | 468 | |
551 | { | 469 | // This is a kludge to get avatar movement updated. |
552 | // If the object is done colliding, see that it's removed from the colliding list | 470 | // Don't send collisions only if there were collisions -- send everytime. |
553 | ObjectsWithNoMoreCollisions.Add(bsp); | 471 | // ODE sends collisions even if there are none and this is used to update |
554 | } | 472 | // avatar animations and stuff. |
555 | } | 473 | // foreach (BSCharacter bsc in m_avatarsWithCollisions) |
556 | 474 | // bsc.SendCollisions(); | |
557 | // This is a kludge to get avatar movement updates. | 475 | foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) |
558 | // The simulator expects collisions for avatars even if there are have been no collisions. | 476 | kvp.Value.SendCollisions(); |
559 | // The event updates avatar animations and stuff. | 477 | m_avatarsWithCollisions.Clear(); |
560 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
561 | foreach (BSPhysObject bsp in m_avatars) | ||
562 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
563 | bsp.SendCollisions(); | ||
564 | |||
565 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
566 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
567 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
568 | { | ||
569 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
570 | ObjectsWithCollisions.Remove(po); | ||
571 | ObjectsWithNoMoreCollisions.Clear(); | ||
572 | } | ||
573 | 478 | ||
574 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 479 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
575 | if (updatedEntityCount > 0) | 480 | if (updatedEntityCount > 0) |
@@ -577,310 +482,320 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
577 | for (int ii = 0; ii < updatedEntityCount; ii++) | 482 | for (int ii = 0; ii < updatedEntityCount; ii++) |
578 | { | 483 | { |
579 | EntityProperties entprop = m_updateArray[ii]; | 484 | EntityProperties entprop = m_updateArray[ii]; |
580 | BSPhysObject pobj; | 485 | BSPrim prim; |
581 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | 486 | if (m_prims.TryGetValue(entprop.ID, out prim)) |
487 | { | ||
488 | prim.UpdateProperties(entprop); | ||
489 | continue; | ||
490 | } | ||
491 | BSCharacter actor; | ||
492 | if (m_avatars.TryGetValue(entprop.ID, out actor)) | ||
582 | { | 493 | { |
583 | pobj.UpdateProperties(entprop); | 494 | actor.UpdateProperties(entprop); |
495 | continue; | ||
584 | } | 496 | } |
585 | } | 497 | } |
586 | } | 498 | } |
587 | 499 | ||
588 | ProcessPostStepTaints(); | 500 | // If enabled, call into the physics engine to dump statistics |
589 | 501 | if (m_detailedStatsStep > 0) | |
590 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 502 | { |
591 | // Only enable this in a limited test world with few objects. | 503 | if ((m_simulationStep % m_detailedStatsStep) == 0) |
592 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 504 | { |
505 | BulletSimAPI.DumpBulletStatistics(); | ||
506 | } | ||
507 | } | ||
593 | 508 | ||
594 | // The physics engine returns the number of milliseconds it simulated this call. | 509 | // this is a waste since the outside routine also calcuates the physics simulation |
595 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 510 | // period. TODO: There should be a way of computing physics frames from simulator computation. |
596 | // We multiply by 55 to give a recognizable running rate (55 or less). | 511 | // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); |
597 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 512 | // return (timeStep * (float)simulateTotalTime); |
598 | // return timeStep * 1000 * 55; | 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); | ||
599 | } | 521 | } |
600 | 522 | ||
601 | // Something has collided | 523 | // Something has collided |
602 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) | 524 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) |
603 | { | 525 | { |
604 | if (localID <= TerrainManager.HighestTerrainID) | 526 | if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) |
605 | { | 527 | { |
606 | return; // don't send collisions to the terrain | 528 | return; // don't send collisions to the terrain |
607 | } | 529 | } |
608 | 530 | ||
609 | BSPhysObject collider; | 531 | ActorTypes type = ActorTypes.Prim; |
610 | if (!PhysObjects.TryGetValue(localID, out collider)) | 532 | if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) |
611 | { | 533 | type = ActorTypes.Ground; |
612 | // If the object that is colliding cannot be found, just ignore the collision. | 534 | else if (m_avatars.ContainsKey(collidingWith)) |
613 | DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); | 535 | type = ActorTypes.Agent; |
536 | |||
537 | BSPrim prim; | ||
538 | if (m_prims.TryGetValue(localID, out prim)) { | ||
539 | prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration); | ||
540 | m_primsWithCollisions.Add(prim); | ||
614 | return; | 541 | return; |
615 | } | 542 | } |
616 | 543 | BSCharacter actor; | |
617 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 544 | if (m_avatars.TryGetValue(localID, out actor)) { |
618 | BSPhysObject collidee = null; | 545 | actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); |
619 | PhysObjects.TryGetValue(collidingWith, out collidee); | 546 | m_avatarsWithCollisions.Add(actor); |
620 | 547 | return; | |
621 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | ||
622 | |||
623 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | ||
624 | { | ||
625 | // If a collision was posted, remember to send it to the simulator | ||
626 | ObjectsWithCollisions.Add(collider); | ||
627 | } | 548 | } |
628 | |||
629 | return; | 549 | return; |
630 | } | 550 | } |
631 | 551 | ||
632 | #endregion // Simulation | ||
633 | |||
634 | public override void GetResults() { } | 552 | public override void GetResults() { } |
635 | 553 | ||
636 | #region Terrain | ||
637 | |||
638 | public override void SetTerrain(float[] heightMap) { | 554 | public override void SetTerrain(float[] heightMap) { |
639 | TerrainManager.SetTerrain(heightMap); | 555 | m_heightMap = heightMap; |
556 | this.TaintedObject("BSScene.SetTerrain", delegate() | ||
557 | { | ||
558 | BulletSimAPI.SetHeightmap(m_worldID, m_heightMap); | ||
559 | }); | ||
640 | } | 560 | } |
641 | 561 | ||
642 | public override void SetWaterLevel(float baseheight) | 562 | // Someday we will have complex terrain with caves and tunnels |
563 | // For the moment, it's flat and convex | ||
564 | public float GetTerrainHeightAtXYZ(Vector3 loc) | ||
643 | { | 565 | { |
644 | m_waterLevel = baseheight; | 566 | return GetTerrainHeightAtXY(loc.X, loc.Y); |
645 | } | ||
646 | // Someday.... | ||
647 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
648 | { | ||
649 | return m_waterLevel; | ||
650 | } | 567 | } |
651 | 568 | ||
652 | public override void DeleteTerrain() | 569 | public float GetTerrainHeightAtXY(float tX, float tY) |
653 | { | 570 | { |
654 | // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); | 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)]; | ||
655 | } | 574 | } |
656 | 575 | ||
657 | // Although no one seems to check this, I do support combining. | 576 | public override void SetWaterLevel(float baseheight) |
658 | public override bool SupportsCombining() | ||
659 | { | 577 | { |
660 | return TerrainManager.SupportsCombining(); | 578 | m_waterLevel = baseheight; |
579 | // TODO: pass to physics engine so things will float? | ||
661 | } | 580 | } |
662 | // This call says I am a child to region zero in a mega-region. 'pScene' is that | 581 | public float GetWaterLevel() |
663 | // of region zero, 'offset' is my offset from regions zero's origin, and | ||
664 | // 'extents' is the largest XY that is handled in my region. | ||
665 | public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
666 | { | 582 | { |
667 | TerrainManager.Combine(pScene, offset, extents); | 583 | return m_waterLevel; |
668 | } | 584 | } |
669 | 585 | ||
670 | // Unhook all the combining that I know about. | 586 | public override void DeleteTerrain() |
671 | public override void UnCombine(PhysicsScene pScene) | ||
672 | { | 587 | { |
673 | TerrainManager.UnCombine(pScene); | 588 | // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); |
674 | } | 589 | } |
675 | 590 | ||
676 | #endregion // Terrain | 591 | public override void Dispose() |
677 | |||
678 | public override Dictionary<uint, float> GetTopColliders() | ||
679 | { | 592 | { |
680 | return new Dictionary<uint, float>(); | 593 | // m_log.DebugFormat("{0}: Dispose()", LogHeader); |
681 | } | ||
682 | 594 | ||
683 | public override bool IsThreaded { get { return false; } } | 595 | // make sure no stepping happens while we're deleting stuff |
596 | m_initialized = false; | ||
684 | 597 | ||
685 | #region Taints | 598 | foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) |
599 | { | ||
600 | kvp.Value.Destroy(); | ||
601 | } | ||
602 | m_avatars.Clear(); | ||
686 | 603 | ||
687 | // Calls to the PhysicsActors can't directly call into the physics engine | 604 | foreach (KeyValuePair<uint, BSPrim> kvp in m_prims) |
688 | // because it might be busy. We delay changes to a known time. | 605 | { |
689 | // We rely on C#'s closure to save and restore the context for the delegate. | 606 | kvp.Value.Destroy(); |
690 | public void TaintedObject(String ident, TaintCallback callback) | 607 | } |
691 | { | 608 | m_prims.Clear(); |
692 | if (!m_initialized) return; | ||
693 | 609 | ||
694 | lock (_taintLock) | 610 | // Now that the prims are all cleaned up, there should be no constraints left |
611 | if (m_constraintCollection != null) | ||
695 | { | 612 | { |
696 | _taintOperations.Add(new TaintCallbackEntry(ident, callback)); | 613 | m_constraintCollection.Dispose(); |
614 | m_constraintCollection = null; | ||
697 | } | 615 | } |
698 | 616 | ||
699 | return; | 617 | // Anything left in the unmanaged code should be cleaned out |
700 | } | 618 | BulletSimAPI.Shutdown(WorldID); |
701 | 619 | ||
702 | // Sometimes a potentially tainted operation can be used in and out of taint time. | 620 | // Not logging any more |
703 | // This routine executes the command immediately if in taint-time otherwise it is queued. | 621 | PhysicsLogging.Close(); |
704 | public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) | ||
705 | { | ||
706 | if (inTaintTime) | ||
707 | callback(); | ||
708 | else | ||
709 | TaintedObject(ident, callback); | ||
710 | } | 622 | } |
711 | 623 | ||
712 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | 624 | public override Dictionary<uint, float> GetTopColliders() |
713 | // a callback into itself to do the actual property change. That callback is called | ||
714 | // here just before the physics engine is called to step the simulation. | ||
715 | public void ProcessTaints() | ||
716 | { | 625 | { |
717 | InTaintTime = true; | 626 | return new Dictionary<uint, float>(); |
718 | ProcessRegularTaints(); | ||
719 | ProcessPostTaintTaints(); | ||
720 | InTaintTime = false; | ||
721 | } | 627 | } |
722 | 628 | ||
723 | private void ProcessRegularTaints() | 629 | public override bool IsThreaded { get { return false; } } |
630 | |||
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) | ||
724 | { | 637 | { |
725 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | 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) | ||
726 | { | 645 | { |
727 | int taintCount = m_taintsToProcessPerStep; | 646 | // Render sculpties as boxes |
728 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | 647 | return false; |
729 | while (_taintOperations.Count > 0 && taintCount-- > 0) | 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)) | ||
730 | { | 657 | { |
731 | bool gotOne = false; | 658 | |
732 | lock (_taintLock) | 659 | if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
733 | { | 660 | && pbs.ProfileHollow == 0 |
734 | if (_taintOperations.Count > 0) | 661 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 |
735 | { | 662 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 |
736 | oneCallback = _taintOperations[0]; | 663 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 |
737 | _taintOperations.RemoveAt(0); | 664 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
738 | gotOne = true; | 665 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) |
739 | } | ||
740 | } | ||
741 | if (gotOne) | ||
742 | { | 666 | { |
743 | try | 667 | return false; |
744 | { | ||
745 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); | ||
746 | oneCallback.callback(); | ||
747 | } | ||
748 | catch (Exception e) | ||
749 | { | ||
750 | DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
751 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
752 | } | ||
753 | } | 668 | } |
754 | } | 669 | } |
755 | /* | 670 | } |
756 | // swizzle a new list into the list location so we can process what's there | 671 | |
757 | List<TaintCallbackEntry> oldList; | 672 | /* TODO: verify that the mesher will now do all these shapes |
758 | lock (_taintLock) | 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) | ||
759 | { | 704 | { |
760 | oldList = _taintedObjects; | 705 | iPropertiesNotSupportedDefault++; |
761 | _taintedObjects = new List<TaintCallbackEntry>(); | ||
762 | } | 706 | } |
763 | 707 | } | |
764 | foreach (TaintCallbackEntry tcbe in oldList) | 708 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) |
709 | { | ||
710 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
765 | { | 711 | { |
766 | try | 712 | iPropertiesNotSupportedDefault++; |
767 | { | 713 | } |
768 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | 714 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits |
769 | tcbe.callback(); | 715 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) |
770 | } | 716 | { |
771 | catch (Exception e) | 717 | iPropertiesNotSupportedDefault++; |
772 | { | ||
773 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
774 | } | ||
775 | } | 718 | } |
776 | oldList.Clear(); | ||
777 | */ | ||
778 | } | 719 | } |
779 | } | 720 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) |
780 | |||
781 | // Schedule an update to happen after all the regular taints are processed. | ||
782 | // Note that new requests for the same operation ("ident") for the same object ("ID") | ||
783 | // will replace any previous operation by the same object. | ||
784 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) | ||
785 | { | ||
786 | if (!m_initialized) return; | ||
787 | |||
788 | string uniqueIdent = ident + "-" + ID.ToString(); | ||
789 | lock (_taintLock) | ||
790 | { | 721 | { |
791 | _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); | 722 | if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) |
723 | { | ||
724 | iPropertiesNotSupportedDefault++; | ||
725 | } | ||
792 | } | 726 | } |
793 | 727 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | |
794 | return; | ||
795 | } | ||
796 | |||
797 | private void ProcessPostTaintTaints() | ||
798 | { | ||
799 | if (_postTaintOperations.Count > 0) | ||
800 | { | 728 | { |
801 | Dictionary<string, TaintCallbackEntry> oldList; | 729 | if (pbs.PathCurve == (byte)Extrusion.Straight) |
802 | lock (_taintLock) | ||
803 | { | 730 | { |
804 | oldList = _postTaintOperations; | 731 | iPropertiesNotSupportedDefault++; |
805 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
806 | } | 732 | } |
807 | 733 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | |
808 | foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList) | ||
809 | { | 734 | { |
810 | try | 735 | iPropertiesNotSupportedDefault++; |
811 | { | ||
812 | DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG | ||
813 | kvp.Value.callback(); | ||
814 | } | ||
815 | catch (Exception e) | ||
816 | { | ||
817 | m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); | ||
818 | } | ||
819 | } | 736 | } |
820 | oldList.Clear(); | ||
821 | } | 737 | } |
738 | if (iPropertiesNotSupportedDefault == 0) | ||
739 | { | ||
740 | return false; | ||
741 | } | ||
742 | */ | ||
743 | return true; | ||
822 | } | 744 | } |
823 | 745 | ||
824 | public void PostStepTaintObject(String ident, TaintCallback callback) | 746 | // 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. | ||
748 | // We rely on C#'s closure to save and restore the context for the delegate. | ||
749 | public void TaintedObject(String ident, TaintCallback callback) | ||
825 | { | 750 | { |
826 | if (!m_initialized) return; | 751 | if (!m_initialized) return; |
827 | 752 | ||
828 | lock (_taintLock) | 753 | lock (_taintLock) |
829 | { | 754 | _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); |
830 | _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
831 | } | ||
832 | |||
833 | return; | 755 | return; |
834 | } | 756 | } |
835 | 757 | ||
836 | private void ProcessPostStepTaints() | 758 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues |
759 | // a callback into itself to do the actual property change. That callback is called | ||
760 | // here just before the physics engine is called to step the simulation. | ||
761 | public void ProcessTaints() | ||
837 | { | 762 | { |
838 | if (_postStepOperations.Count > 0) | 763 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process |
839 | { | 764 | { |
765 | // swizzle a new list into the list location so we can process what's there | ||
840 | List<TaintCallbackEntry> oldList; | 766 | List<TaintCallbackEntry> oldList; |
841 | lock (_taintLock) | 767 | lock (_taintLock) |
842 | { | 768 | { |
843 | oldList = _postStepOperations; | 769 | oldList = _taintedObjects; |
844 | _postStepOperations = new List<TaintCallbackEntry>(); | 770 | _taintedObjects = new List<TaintCallbackEntry>(); |
845 | } | 771 | } |
846 | 772 | ||
847 | foreach (TaintCallbackEntry tcbe in oldList) | 773 | foreach (TaintCallbackEntry tcbe in oldList) |
848 | { | 774 | { |
849 | try | 775 | try |
850 | { | 776 | { |
851 | DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
852 | tcbe.callback(); | 777 | tcbe.callback(); |
853 | } | 778 | } |
854 | catch (Exception e) | 779 | catch (Exception e) |
855 | { | 780 | { |
856 | m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | 781 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); |
857 | } | 782 | } |
858 | } | 783 | } |
859 | oldList.Clear(); | 784 | oldList.Clear(); |
860 | } | 785 | } |
861 | } | 786 | } |
862 | 787 | ||
863 | public bool AssertInTaintTime(string whereFrom) | ||
864 | { | ||
865 | if (!InTaintTime) | ||
866 | { | ||
867 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | ||
868 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | ||
869 | Util.PrintCallStack(); | ||
870 | } | ||
871 | return InTaintTime; | ||
872 | } | ||
873 | |||
874 | #endregion // Taints | ||
875 | |||
876 | #region Vehicles | 788 | #region Vehicles |
877 | 789 | ||
878 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) | 790 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) |
879 | { | 791 | { |
880 | RemoveVehiclePrim(vehic); | 792 | if (newType == Vehicle.TYPE_NONE) |
881 | if (newType != Vehicle.TYPE_NONE) | ||
882 | { | 793 | { |
883 | // make it so the scene will call us each tick to do vehicle things | 794 | RemoveVehiclePrim(vehic); |
795 | } | ||
796 | else | ||
797 | { | ||
798 | // make it so the scene will call us each tick to do vehicle things | ||
884 | AddVehiclePrim(vehic); | 799 | AddVehiclePrim(vehic); |
885 | } | 800 | } |
886 | } | 801 | } |
@@ -912,22 +827,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
912 | } | 827 | } |
913 | 828 | ||
914 | // Some prims have extra vehicle actions | 829 | // Some prims have extra vehicle actions |
915 | // Called at taint time! | 830 | // no locking because only called when physics engine is not busy |
916 | private void ProcessVehicles(float timeStep) | 831 | private void ProcessVehicles(float timeStep) |
917 | { | 832 | { |
918 | foreach (BSPhysObject pobj in m_vehicles) | 833 | foreach (BSPrim prim in m_vehicles) |
919 | { | 834 | { |
920 | pobj.StepVehicle(timeStep); | 835 | prim.StepVehicle(timeStep); |
921 | } | 836 | } |
922 | } | 837 | } |
923 | #endregion Vehicles | 838 | #endregion Vehicles |
924 | 839 | ||
925 | #region INI and command line parameter processing | 840 | #region Parameters |
926 | 841 | ||
927 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | 842 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); |
928 | delegate float ParamGet(BSScene scene); | 843 | delegate float ParamGet(BSScene scene); |
929 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | 844 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); |
930 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
931 | 845 | ||
932 | private struct ParameterDefn | 846 | private struct ParameterDefn |
933 | { | 847 | { |
@@ -937,7 +851,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
937 | public ParamUser userParam; // get the value from the configuration file | 851 | public ParamUser userParam; // get the value from the configuration file |
938 | public ParamGet getter; // return the current value stored for this parameter | 852 | public ParamGet getter; // return the current value stored for this parameter |
939 | public ParamSet setter; // set the current value for this parameter | 853 | public ParamSet setter; // set the current value for this parameter |
940 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
941 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | 854 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) |
942 | { | 855 | { |
943 | name = n; | 856 | name = n; |
@@ -946,17 +859,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
946 | userParam = u; | 859 | userParam = u; |
947 | getter = g; | 860 | getter = g; |
948 | setter = s; | 861 | setter = s; |
949 | onObject = null; | ||
950 | } | ||
951 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
952 | { | ||
953 | name = n; | ||
954 | desc = d; | ||
955 | defaultValue = v; | ||
956 | userParam = u; | ||
957 | getter = g; | ||
958 | setter = s; | ||
959 | onObject = o; | ||
960 | } | 862 | } |
961 | } | 863 | } |
962 | 864 | ||
@@ -967,7 +869,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
967 | // getters and setters. | 869 | // getters and setters. |
968 | // It is easiest to find an existing definition and copy it. | 870 | // It is easiest to find an existing definition and copy it. |
969 | // Parameter values are floats. Booleans are converted to a floating value. | 871 | // Parameter values are floats. Booleans are converted to a floating value. |
970 | // | 872 | // |
971 | // A ParameterDefn() takes the following parameters: | 873 | // A ParameterDefn() takes the following parameters: |
972 | // -- the text name of the parameter. This is used for console input and ini file. | 874 | // -- the text name of the parameter. This is used for console input and ini file. |
973 | // -- a short text description of the parameter. This shows up in the console listing. | 875 | // -- a short text description of the parameter. This shows up in the console listing. |
@@ -978,7 +880,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
978 | // | 880 | // |
979 | // The single letter parameters for the delegates are: | 881 | // The single letter parameters for the delegates are: |
980 | // s = BSScene | 882 | // s = BSScene |
981 | // o = BSPhysObject | ||
982 | // p = string parameter name | 883 | // p = string parameter name |
983 | // l = localID of referenced object | 884 | // l = localID of referenced object |
984 | // v = float value | 885 | // v = float value |
@@ -987,40 +888,25 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
987 | { | 888 | { |
988 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | 889 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", |
989 | ConfigurationParameters.numericTrue, | 890 | ConfigurationParameters.numericTrue, |
990 | (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, | 891 | (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, |
991 | (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); }, | 892 | (s) => { return s.NumericBool(s._meshSculptedPrim); }, |
992 | (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ), | 893 | (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), |
993 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | 894 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", |
994 | ConfigurationParameters.numericFalse, | 895 | ConfigurationParameters.numericFalse, |
995 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | 896 | (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, |
996 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | 897 | (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, |
997 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | 898 | (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), |
998 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
999 | ConfigurationParameters.numericTrue, | ||
1000 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1001 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
1002 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
1003 | 899 | ||
1004 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 900 | new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
1005 | 8f, | 901 | 8f, |
1006 | (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); }, | 902 | (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, |
1007 | (s) => { return s.MeshLOD; }, | 903 | (s) => { return (float)s.m_meshLOD; }, |
1008 | (s,p,l,v) => { s.MeshLOD = v; } ), | 904 | (s,p,l,v) => { s.m_meshLOD = (int)v; } ), |
1009 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | 905 | new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", |
1010 | 16f, | ||
1011 | (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
1012 | (s) => { return s.MeshMegaPrimLOD; }, | ||
1013 | (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ), | ||
1014 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
1015 | 10f, | ||
1016 | (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
1017 | (s) => { return s.MeshMegaPrimThreshold; }, | ||
1018 | (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ), | ||
1019 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
1020 | 32f, | 906 | 32f, |
1021 | (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); }, | 907 | (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, |
1022 | (s) => { return s.SculptLOD; }, | 908 | (s) => { return (float)s.m_sculptLOD; }, |
1023 | (s,p,l,v) => { s.SculptLOD = v; } ), | 909 | (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), |
1024 | 910 | ||
1025 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | 911 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", |
1026 | 10f, | 912 | 10f, |
@@ -1042,16 +928,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1042 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | 928 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, |
1043 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | 929 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, |
1044 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | 930 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), |
1045 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
1046 | 100f, | ||
1047 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
1048 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
1049 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
1050 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | 931 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", |
1051 | 10000.01f, | 932 | 10000.01f, |
1052 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | 933 | (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, |
1053 | (s) => { return (float)s.MaximumObjectMass; }, | 934 | (s) => { return (float)s.m_maximumObjectMass; }, |
1054 | (s,p,l,v) => { s.MaximumObjectMass = v; } ), | 935 | (s,p,l,v) => { s.m_maximumObjectMass = v; } ), |
1055 | 936 | ||
1056 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | 937 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", |
1057 | 2200f, | 938 | 2200f, |
@@ -1088,118 +969,104 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1088 | -9.80665f, | 969 | -9.80665f, |
1089 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | 970 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, |
1090 | (s) => { return s.m_params[0].gravity; }, | 971 | (s) => { return s.m_params[0].gravity; }, |
1091 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | 972 | (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), |
1092 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
1093 | 973 | ||
1094 | 974 | ||
1095 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | 975 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", |
1096 | 0f, | 976 | 0f, |
1097 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | 977 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, |
1098 | (s) => { return s.m_params[0].linearDamping; }, | 978 | (s) => { return s.m_params[0].linearDamping; }, |
1099 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, | 979 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), |
1100 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ), | ||
1101 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | 980 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |
1102 | 0f, | 981 | 0f, |
1103 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | 982 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, |
1104 | (s) => { return s.m_params[0].angularDamping; }, | 983 | (s) => { return s.m_params[0].angularDamping; }, |
1105 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, | 984 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), |
1106 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ), | ||
1107 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | 985 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", |
1108 | 0.2f, | 986 | 0.2f, |
1109 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | 987 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, |
1110 | (s) => { return s.m_params[0].deactivationTime; }, | 988 | (s) => { return s.m_params[0].deactivationTime; }, |
1111 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, | 989 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), |
1112 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||
1113 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | 990 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |
1114 | 0.8f, | 991 | 0.8f, |
1115 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | 992 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, |
1116 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | 993 | (s) => { return s.m_params[0].linearSleepingThreshold; }, |
1117 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, | 994 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), |
1118 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1119 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | 995 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |
1120 | 1.0f, | 996 | 1.0f, |
1121 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | 997 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, |
1122 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | 998 | (s) => { return s.m_params[0].angularSleepingThreshold; }, |
1123 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, | 999 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), |
1124 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1125 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | 1000 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |
1126 | 0f, // set to zero to disable | 1001 | 0f, // set to zero to disable |
1127 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | 1002 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, |
1128 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | 1003 | (s) => { return s.m_params[0].ccdMotionThreshold; }, |
1129 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, | 1004 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), |
1130 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||
1131 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | 1005 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , |
1132 | 0f, | 1006 | 0f, |
1133 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | 1007 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, |
1134 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | 1008 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, |
1135 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, | 1009 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), |
1136 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||
1137 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | 1010 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , |
1138 | 0.1f, | 1011 | 0.1f, |
1139 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | 1012 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, |
1140 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | 1013 | (s) => { return s.m_params[0].contactProcessingThreshold; }, |
1141 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | 1014 | (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), |
1142 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||
1143 | 1015 | ||
1144 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1016 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1145 | 0.5f, | 1017 | 0.5f, |
1146 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1018 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
1147 | (s) => { return s.m_params[0].terrainFriction; }, | 1019 | (s) => { return s.m_params[0].terrainFriction; }, |
1148 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | 1020 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), |
1149 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | 1021 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , |
1150 | 0.8f, | 1022 | 0.8f, |
1151 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | 1023 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, |
1152 | (s) => { return s.m_params[0].terrainHitFraction; }, | 1024 | (s) => { return s.m_params[0].terrainHitFraction; }, |
1153 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), | 1025 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), |
1154 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | 1026 | new ParameterDefn("TerrainRestitution", "Bouncyness" , |
1155 | 0f, | 1027 | 0f, |
1156 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1028 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
1157 | (s) => { return s.m_params[0].terrainRestitution; }, | 1029 | (s) => { return s.m_params[0].terrainRestitution; }, |
1158 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | 1030 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), |
1159 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1031 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
1160 | 0.2f, | 1032 | 0.5f, |
1161 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1033 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
1162 | (s) => { return s.m_params[0].avatarFriction; }, | 1034 | (s) => { return s.m_params[0].avatarFriction; }, |
1163 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1035 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1164 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1165 | 10f, | ||
1166 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1167 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1168 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
1169 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | 1036 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |
1170 | 60f, | 1037 | 60f, |
1171 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | 1038 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, |
1172 | (s) => { return s.m_params[0].avatarDensity; }, | 1039 | (s) => { return s.m_params[0].avatarDensity; }, |
1173 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ), | 1040 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), |
1174 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | 1041 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", |
1175 | 0f, | 1042 | 0f, |
1176 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, | 1043 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, |
1177 | (s) => { return s.m_params[0].avatarRestitution; }, | 1044 | (s) => { return s.m_params[0].avatarRestitution; }, |
1178 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), | 1045 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), |
1179 | new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", | 1046 | new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", |
1180 | 0.37f, | 1047 | 0.37f, |
1181 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, | 1048 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, |
1182 | (s) => { return s.m_params[0].avatarCapsuleRadius; }, | 1049 | (s) => { return s.m_params[0].avatarCapsuleRadius; }, |
1183 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), | 1050 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), |
1184 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | 1051 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", |
1185 | 1.5f, | 1052 | 1.5f, |
1186 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, | 1053 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, |
1187 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, | 1054 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, |
1188 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), | 1055 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), |
1189 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 1056 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |
1190 | 0.1f, | 1057 | 0.1f, |
1191 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, | 1058 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, |
1192 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | 1059 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, |
1193 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | 1060 | (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), |
1194 | 1061 | ||
1195 | 1062 | ||
1196 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 1063 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
1197 | 0f, | 1064 | 0f, // zero to disable |
1198 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | 1065 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, |
1199 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, | 1066 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, |
1200 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), | 1067 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), |
1201 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | 1068 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", |
1202 | 0f, | 1069 | 0f, // zero to disable |
1203 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | 1070 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, |
1204 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, | 1071 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, |
1205 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), | 1072 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), |
@@ -1214,12 +1081,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1214 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, | 1081 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, |
1215 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), | 1082 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), |
1216 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | 1083 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", |
1217 | ConfigurationParameters.numericTrue, | 1084 | ConfigurationParameters.numericFalse, |
1218 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1085 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
1219 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, | 1086 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, |
1220 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), | 1087 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), |
1221 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | 1088 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", |
1222 | ConfigurationParameters.numericTrue, | 1089 | ConfigurationParameters.numericFalse, |
1223 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1090 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
1224 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, | 1091 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, |
1225 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), | 1092 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), |
@@ -1234,11 +1101,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1234 | (s) => { return s.m_params[0].numberOfSolverIterations; }, | 1101 | (s) => { return s.m_params[0].numberOfSolverIterations; }, |
1235 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), | 1102 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), |
1236 | 1103 | ||
1237 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
1238 | (float)BSLinkset.LinksetImplementation.Compound, | ||
1239 | (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, | ||
1240 | (s) => { return s.m_params[0].linksetImplementation; }, | ||
1241 | (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), | ||
1242 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | 1104 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |
1243 | ConfigurationParameters.numericFalse, | 1105 | ConfigurationParameters.numericFalse, |
1244 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1106 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
@@ -1259,27 +1121,28 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1259 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | 1121 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, |
1260 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | 1122 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, |
1261 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | 1123 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), |
1262 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | 1124 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0", |
1263 | 0.1f, | 1125 | 0.0f, |
1264 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | 1126 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, |
1265 | (s) => { return s.m_params[0].linkConstraintCFM; }, | 1127 | (s) => { return s.m_params[0].linkConstraintCFM; }, |
1266 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | 1128 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), |
1267 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | 1129 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
1268 | 0.1f, | 1130 | 0.2f, |
1269 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | 1131 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, |
1270 | (s) => { return s.m_params[0].linkConstraintERP; }, | 1132 | (s) => { return s.m_params[0].linkConstraintERP; }, |
1271 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | 1133 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), |
1272 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
1273 | 40, | ||
1274 | (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
1275 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | ||
1276 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | ||
1277 | 1134 | ||
1278 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | 1135 | new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", |
1279 | 0f, | 1136 | 0f, |
1280 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | 1137 | (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, |
1281 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, | 1138 | (s) => { return (float)s.m_detailedStatsStep; }, |
1282 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), | 1139 | (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 | |||
1283 | }; | 1146 | }; |
1284 | 1147 | ||
1285 | // Convert a boolean to our numeric true and false values | 1148 | // Convert a boolean to our numeric true and false values |
@@ -1337,12 +1200,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1337 | 1200 | ||
1338 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | 1201 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; |
1339 | 1202 | ||
1340 | // This creates an array in the correct format for returning the list of | ||
1341 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
1342 | private void BuildParameterTable() | 1203 | private void BuildParameterTable() |
1343 | { | 1204 | { |
1344 | if (SettableParameters.Length < ParameterDefinitions.Length) | 1205 | if (SettableParameters.Length < ParameterDefinitions.Length) |
1345 | { | 1206 | { |
1207 | |||
1346 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | 1208 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); |
1347 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | 1209 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) |
1348 | { | 1210 | { |
@@ -1387,54 +1249,60 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1387 | return ret; | 1249 | return ret; |
1388 | } | 1250 | } |
1389 | 1251 | ||
1252 | // 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) | ||
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 | { | ||
1263 | List<uint> operateOn; | ||
1264 | lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); | ||
1265 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
1266 | } | ||
1267 | |||
1390 | // update all the localIDs specified | 1268 | // update all the localIDs specified |
1391 | // If the local ID is APPLY_TO_NONE, just change the default value | 1269 | // If the local ID is APPLY_TO_NONE, just change the default value |
1392 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | 1270 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |
1393 | // If the localID is a specific object, apply the parameter change to only that object | 1271 | // If the localID is a specific object, apply the parameter change to only that object |
1394 | private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) | 1272 | protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) |
1395 | { | 1273 | { |
1396 | List<uint> objectIDs = new List<uint>(); | ||
1397 | switch (localID) | 1274 | switch (localID) |
1398 | { | 1275 | { |
1399 | case PhysParameterEntry.APPLY_TO_NONE: | 1276 | case PhysParameterEntry.APPLY_TO_NONE: |
1400 | defaultLoc = val; // setting only the default value | 1277 | defaultLoc = val; // setting only the default value |
1401 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
1402 | objectIDs.Add(TERRAIN_ID); | ||
1403 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1404 | break; | 1278 | break; |
1405 | case PhysParameterEntry.APPLY_TO_ALL: | 1279 | case PhysParameterEntry.APPLY_TO_ALL: |
1406 | defaultLoc = val; // setting ALL also sets the default value | 1280 | defaultLoc = val; // setting ALL also sets the default value |
1407 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | 1281 | List<uint> objectIDs = lIDs; |
1408 | TaintedUpdateParameter(parm, objectIDs, val); | 1282 | string xparm = parm.ToLower(); |
1283 | float xval = val; | ||
1284 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1285 | foreach (uint lID in objectIDs) | ||
1286 | { | ||
1287 | BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); | ||
1288 | } | ||
1289 | }); | ||
1409 | break; | 1290 | break; |
1410 | default: | 1291 | default: |
1411 | // setting only one localID | 1292 | // setting only one localID |
1412 | objectIDs.Add(localID); | 1293 | TaintedUpdateParameter(parm, localID, val); |
1413 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1414 | break; | 1294 | break; |
1415 | } | 1295 | } |
1416 | } | 1296 | } |
1417 | 1297 | ||
1418 | // schedule the actual updating of the paramter to when the phys engine is not busy | 1298 | // schedule the actual updating of the paramter to when the phys engine is not busy |
1419 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) | 1299 | protected void TaintedUpdateParameter(string parm, uint localID, float val) |
1420 | { | 1300 | { |
1301 | uint xlocalID = localID; | ||
1302 | string xparm = parm.ToLower(); | ||
1421 | float xval = val; | 1303 | float xval = val; |
1422 | List<uint> xlIDs = lIDs; | 1304 | TaintedObject("BSScene.TaintedUpdateParameter", delegate() { |
1423 | string xparm = parm; | 1305 | BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); |
1424 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1425 | ParameterDefn thisParam; | ||
1426 | if (TryGetParameter(xparm, out thisParam)) | ||
1427 | { | ||
1428 | if (thisParam.onObject != null) | ||
1429 | { | ||
1430 | foreach (uint lID in xlIDs) | ||
1431 | { | ||
1432 | BSPhysObject theObject = null; | ||
1433 | PhysObjects.TryGetValue(lID, out theObject); | ||
1434 | thisParam.onObject(this, theObject, xval); | ||
1435 | } | ||
1436 | } | ||
1437 | } | ||
1438 | }); | 1306 | }); |
1439 | } | 1307 | } |
1440 | 1308 | ||
@@ -1458,24 +1326,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1458 | 1326 | ||
1459 | #endregion Runtime settable parameters | 1327 | #endregion Runtime settable parameters |
1460 | 1328 | ||
1461 | // Debugging routine for dumping detailed physical information for vehicle prims | ||
1462 | private void DumpVehicles() | ||
1463 | { | ||
1464 | foreach (BSPrim prim in m_vehicles) | ||
1465 | { | ||
1466 | BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); | ||
1467 | BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); | ||
1468 | } | ||
1469 | } | ||
1470 | |||
1471 | // Invoke the detailed logger and output something if it's enabled. | 1329 | // Invoke the detailed logger and output something if it's enabled. |
1472 | public void DetailLog(string msg, params Object[] args) | 1330 | public void DetailLog(string msg, params Object[] args) |
1473 | { | 1331 | { |
1474 | PhysicsLogging.Write(msg, args); | 1332 | PhysicsLogging.Write(msg, args); |
1475 | // Add the Flush() if debugging crashes. Gets all the messages written out. | ||
1476 | PhysicsLogging.Flush(); | ||
1477 | } | 1333 | } |
1478 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1334 | // used to fill in the LocalID when there isn't one |
1479 | public const string DetailLogZero = "0000000000"; | 1335 | public const string DetailLogZero = "0000000000"; |
1480 | 1336 | ||
1481 | } | 1337 | } |