aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/OdeScene.cs4455
1 files changed, 1853 insertions, 2602 deletions
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
index ed2aad4..410463c 100644
--- a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
+++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
@@ -25,52 +25,54 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28// changes for varsize regions 28// Revision 2011/12/13 by Ubit Umarov
29// note that raycasts need to have limited range 29//#define SPAM
30// (even in normal regions)
31// or application thread stack may just blowup
32// see RayCast(ODERayCastRequest req)
33 30
34using System; 31using System;
35using System.Collections.Generic; 32using System.Collections.Generic;
36using System.Diagnostics;
37using System.IO;
38using System.Linq; 33using System.Linq;
39using System.Reflection; 34using System.Reflection;
40using System.Runtime.ExceptionServices;
41using System.Runtime.InteropServices; 35using System.Runtime.InteropServices;
42using System.Threading; 36using System.Threading;
37using System.IO;
38using System.Diagnostics;
43using log4net; 39using log4net;
44using Nini.Config; 40using Nini.Config;
45using Mono.Addins; 41using Mono.Addins;
46using OpenMetaverse; 42using OdeAPI;
47using OpenSim.Framework; 43using OpenSim.Framework;
48using OpenSim.Region.PhysicsModules.SharedBase;
49using OpenSim.Region.Framework.Scenes; 44using OpenSim.Region.Framework.Scenes;
50using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.PhysicsModules.SharedBase;
47using OpenMetaverse;
51 48
52namespace OpenSim.Region.PhysicsModule.ODE 49namespace OpenSim.Region.PhysicsModule.ubOde
53{ 50{
54 public enum StatusIndicators : int 51 // colision flags of things others can colide with
55 { 52 // rays, sensors, probes removed since can't be colided with
56 Generic = 0, 53 // The top space where things are placed provided further selection
57 Start = 1, 54 // ie physical are in active space nonphysical in static
58 End = 2 55 // this should be exclusive as possible
59 }
60 56
61 [Flags] 57 [Flags]
62 public enum CollisionCategories : int 58 public enum CollisionCategories : uint
63 { 59 {
64 Disabled = 0, 60 Disabled = 0,
65 Geom = 0x00000001, 61 //by 'things' types
66 Body = 0x00000002, 62 Space = 0x01,
67 Space = 0x00000004, 63 Geom = 0x02, // aka prim/part
68 Character = 0x00000008, 64 Character = 0x04,
69 Land = 0x00000010, 65 Land = 0x08,
70 Water = 0x00000020, 66 Water = 0x010,
71 Wind = 0x00000040, 67
72 Sensor = 0x00000080, 68 // by state
73 Selected = 0x00000100 69 Phantom = 0x01000,
70 VolumeDtc = 0x02000,
71 Selected = 0x04000,
72 NoShape = 0x08000,
73
74
75 All = 0xffffffff
74 } 76 }
75 77
76 /// <summary> 78 /// <summary>
@@ -91,836 +93,579 @@ namespace OpenSim.Region.PhysicsModule.ODE
91 /// <summary></summary> 93 /// <summary></summary>
92 Plastic = 5, 94 Plastic = 5,
93 /// <summary></summary> 95 /// <summary></summary>
94 Rubber = 6 96 Rubber = 6,
95 }
96 97
97 public class OdeScene : PhysicsScene 98 light = 7 // compatibility with old viewers
99 }
100
101 public enum changes : int
98 { 102 {
99 private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString()); 103 Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?)
100 104 Remove,
101 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); 105 Link, // arg AuroraODEPrim new parent prim or null to delink. Makes the prim part of a object with prim parent as root
102 106 // or removes from a object if arg is null
103 /// <summary> 107 DeLink,
104 /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. 108 Position, // arg Vector3 new position in world coords. Changes prim position. Prim must know if it is root or child
105 /// </summary> 109 Orientation, // arg Quaternion new orientation in world coords. Changes prim position. Prim must know it it is root or child
106 /// <remarks> 110 PosOffset, // not in use
107 /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a 111 // arg Vector3 new position in local coords. Changes prim position in object
108 /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts 112 OriOffset, // not in use
109 /// uses a static cache at the ODE level. 113 // arg Vector3 new position in local coords. Changes prim position in object
110 /// 114 Velocity,
111 /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar 115 TargetVelocity,
112 /// to 116 AngVelocity,
113 /// 117 Acceleration,
114 /// mono() [0x489171] 118 Force,
115 /// mono() [0x4d154f] 119 Torque,
116 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60] 120 Momentum,
117 /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a] 121
118 /// 122 AddForce,
119 /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option 123 AddAngForce,
120 /// causes OpenSimulator to immediately crash with a native stack trace similar to 124 AngLock,
121 /// 125
122 /// mono() [0x489171] 126 Buoyancy,
123 /// mono() [0x4d154f] 127
124 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60] 128 PIDTarget,
125 /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82] 129 PIDTau,
126 /// </remarks> 130 PIDActive,
127 internal static Object UniversalColliderSyncObject = new Object(); 131
128 internal static Object SimulationLock = new Object(); 132 PIDHoverHeight,
129 133 PIDHoverType,
130 /// <summary> 134 PIDHoverTau,
131 /// Is stats collecting enabled for this ODE scene? 135 PIDHoverActive,
132 /// </summary> 136
133 public bool CollectStats { get; set; } 137 Size,
134 138 AvatarSize,
135 /// <summary> 139 Shape,
136 /// Statistics for this scene. 140 PhysRepData,
137 /// </summary> 141 AddPhysRep,
138 private Dictionary<string, float> m_stats = new Dictionary<string, float>(); 142
139 143 CollidesWater,
140 /// <summary> 144 VolumeDtc,
141 /// Stat name for total number of avatars in this ODE scene. 145
142 /// </summary> 146 Physical,
143 public const string ODETotalAvatarsStatName = "ODETotalAvatars"; 147 Phantom,
144 148 Selected,
145 /// <summary> 149 disabled,
146 /// Stat name for total number of prims in this ODE scene. 150 building,
147 /// </summary> 151
148 public const string ODETotalPrimsStatName = "ODETotalPrims"; 152 VehicleType,
149 153 VehicleFloatParam,
150 /// <summary> 154 VehicleVectorParam,
151 /// Stat name for total number of prims with active physics in this ODE scene. 155 VehicleRotationParam,
152 /// </summary> 156 VehicleFlags,
153 public const string ODEActivePrimsStatName = "ODEActivePrims"; 157 SetVehicle,
154 158
155 /// <summary> 159 Null //keep this last used do dim the methods array. does nothing but pulsing the prim
156 /// Stat name for the total time spent in ODE frame processing. 160 }
157 /// </summary>
158 /// <remarks>
159 /// A sanity check for the main scene loop physics time.
160 /// </remarks>
161 public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
162
163 /// <summary>
164 /// Stat name for time spent processing avatar taints per frame
165 /// </summary>
166 public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS";
167
168 /// <summary>
169 /// Stat name for time spent processing prim taints per frame
170 /// </summary>
171 public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS";
172
173 /// <summary>
174 /// Stat name for time spent calculating avatar forces per frame.
175 /// </summary>
176 public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS";
177
178 /// <summary>
179 /// Stat name for time spent calculating prim forces per frame
180 /// </summary>
181 public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS";
182
183 /// <summary>
184 /// Stat name for time spent fulfilling raycasting requests per frame
185 /// </summary>
186 public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS";
187
188 /// <summary>
189 /// Stat name for time spent in native code that actually steps through the simulation.
190 /// </summary>
191 public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
192
193 /// <summary>
194 /// Stat name for the number of milliseconds that ODE spends in native space collision code.
195 /// </summary>
196 public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
197
198 /// <summary>
199 /// Stat name for milliseconds that ODE spends in native geom collision code.
200 /// </summary>
201 public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
202
203 /// <summary>
204 /// Time spent in collision processing that is not spent in native space or geom collision code.
205 /// </summary>
206 public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS";
207
208 /// <summary>
209 /// Stat name for time spent notifying listeners of collisions
210 /// </summary>
211 public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS";
212
213 /// <summary>
214 /// Stat name for milliseconds spent updating avatar position and velocity
215 /// </summary>
216 public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS";
217
218 /// <summary>
219 /// Stat name for the milliseconds spent updating prim position and velocity
220 /// </summary>
221 public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS";
222 161
223 /// <summary> 162 public struct ODEchangeitem
224 /// Stat name for avatar collisions with another entity. 163 {
225 /// </summary> 164 public PhysicsActor actor;
226 public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; 165 public OdeCharacter character;
166 public changes what;
167 public Object arg;
168 }
227 169
228 /// <summary> 170 public class ODEScene : PhysicsScene
229 /// Stat name for prim collisions with another entity. 171 {
230 /// </summary> 172 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
231 public const string ODEPrimContactsStatName = "ODEPrimContacts";
232 173
233 /// <summary> 174 public bool m_OSOdeLib = false;
234 /// Used to hold tick numbers for stat collection purposes. 175 public Scene m_frameWorkScene = null;
235 /// </summary>
236 private int m_nativeCollisionStartTick;
237 176
238 /// <summary> 177// private int threadid = 0;
239 /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback.
240 /// </summary>
241 private bool m_inCollisionTiming;
242 178
243 /// <summary> 179// const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce;
244 /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object
245 /// collisions occured using the _perloopcontact if stats collection is enabled.
246 /// </summary>
247 private int m_tempAvatarCollisionsThisFrame;
248 180
249 /// <summary> 181 const d.ContactFlags comumContactFlags = d.ContactFlags.Bounce | d.ContactFlags.Approx1 | d.ContactFlags.Slip1 | d.ContactFlags.Slip2;
250 /// Used in calculating physics frame time dilation 182 const float comumContactERP = 0.75f;
251 /// </summary> 183 const float comumContactCFM = 0.0001f;
252 private int tickCountFrameRun; 184 const float comumContactSLIP = 0f;
185
186 float frictionMovementMult = 0.8f;
253 187
254 /// <summary> 188 float TerrainBounce = 0.1f;
255 /// Used in calculating physics frame time dilation 189 float TerrainFriction = 0.3f;
256 /// </summary>
257 private int latertickcount;
258 190
259 private Random fluidRandomizer = new Random(Environment.TickCount); 191 public float AvatarFriction = 0;// 0.9f * 0.5f;
260 192
193 // this netx dimensions are only relevant for terrain partition (mega regions)
194 // WorldExtents below has the simulation dimensions
195 // they should be identical except on mega regions
261 private uint m_regionWidth = Constants.RegionSize; 196 private uint m_regionWidth = Constants.RegionSize;
262 private uint m_regionHeight = Constants.RegionSize; 197 private uint m_regionHeight = Constants.RegionSize;
263 198
264 private float ODE_STEPSIZE = 0.0178f; 199 public float ODE_STEPSIZE = 0.020f;
265 private float metersInSpace = 29.9f; 200 public float HalfOdeStep = 0.01f;
201 public int odetimestepMS = 20; // rounded
202 private float metersInSpace = 25.6f;
266 private float m_timeDilation = 1.0f; 203 private float m_timeDilation = 1.0f;
267 204
205 private DateTime m_lastframe;
206 private DateTime m_lastMeshExpire;
207
268 public float gravityx = 0f; 208 public float gravityx = 0f;
269 public float gravityy = 0f; 209 public float gravityy = 0f;
270 public float gravityz = -9.8f; 210 public float gravityz = -9.8f;
271 211
272 public float AvatarTerminalVelocity { get; set; }
273
274 private float contactsurfacelayer = 0.001f;
275
276 private int HashspaceLow = -5;
277 private int HashspaceHigh = 12;
278
279 private float waterlevel = 0f; 212 private float waterlevel = 0f;
280 private int framecount = 0; 213 private int framecount = 0;
281 //private int m_returncollisions = 10;
282
283 private IntPtr contactgroup;
284
285// internal IntPtr WaterGeom;
286
287 private float nmTerrainContactFriction = 255.0f;
288 private float nmTerrainContactBounce = 0.1f;
289 private float nmTerrainContactERP = 0.1025f;
290
291 private float mTerrainContactFriction = 75f;
292 private float mTerrainContactBounce = 0.1f;
293 private float mTerrainContactERP = 0.05025f;
294
295 private float nmAvatarObjectContactFriction = 250f;
296 private float nmAvatarObjectContactBounce = 0.1f;
297
298 private float mAvatarObjectContactFriction = 75f;
299 private float mAvatarObjectContactBounce = 0.1f;
300
301 private float avPIDD = 3200f;
302 private float avPIDP = 1400f;
303 private float avCapRadius = 0.37f;
304 private float avStandupTensor = 2000000f;
305
306 /// <summary>
307 /// true = old compatibility mode with leaning capsule; false = new corrected mode
308 /// </summary>
309 /// <remarks>
310 /// Even when set to false, the capsule still tilts but this is done in a different way.
311 /// </remarks>
312 public bool IsAvCapsuleTilted { get; private set; }
313 214
314 private float avDensity = 80f; 215 private float avDensity = 80f;
315 private float avMovementDivisorWalk = 1.3f; 216 private float avMovementDivisorWalk = 1.3f;
316 private float avMovementDivisorRun = 0.8f; 217 private float avMovementDivisorRun = 0.8f;
317 private float minimumGroundFlightOffset = 3f; 218 private float minimumGroundFlightOffset = 3f;
318 public float maximumMassObject = 10000.01f; 219 public float maximumMassObject = 10000.01f;
220 public float geomDefaultDensity = 10.0f;
319 221
320 public bool meshSculptedPrim = true; 222 public float maximumAngularVelocity = 12.0f; // default 12rad/s
321 public bool forceSimplePrimMeshing = false; 223 public float maxAngVelocitySQ = 144f; // squared value
322
323 public float meshSculptLOD = 32;
324 public float MeshSculptphysicalLOD = 16;
325
326 public float geomDefaultDensity = 10.000006836f;
327
328 public int geomContactPointsStartthrottle = 3;
329 public int geomUpdatesPerThrottledUpdate = 15;
330 private const int avatarExpectedContacts = 3;
331 224
332 public float bodyPIDD = 35f; 225 public float bodyPIDD = 35f;
333 public float bodyPIDG = 25; 226 public float bodyPIDG = 25;
334 227
335 public int bodyFramesAutoDisable = 20; 228 public int bodyFramesAutoDisable = 5;
336
337 private bool m_filterCollisions = true;
338 229
339 private d.NearCallback nearCallback; 230 private d.NearCallback nearCallback;
340 public d.TriCallback triCallback;
341 public d.TriArrayCallback triArrayCallback;
342
343 /// <summary>
344 /// Avatars in the physics scene.
345 /// </summary>
346 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
347
348 /// <summary>
349 /// Prims in the physics scene.
350 /// </summary>
351 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
352
353 /// <summary>
354 /// Prims in the physics scene that are subject to physics, not just collisions.
355 /// </summary>
356 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
357
358 /// <summary>
359 /// Prims that the simulator has created/deleted/updated and so need updating in ODE.
360 /// </summary>
361 private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>();
362
363 /// <summary>
364 /// Record a character that has taints to be processed.
365 /// </summary>
366 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
367
368 /// <summary>
369 /// Keep record of contacts in the physics loop so that we can remove duplicates.
370 /// </summary>
371 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
372 231
373 /// <summary> 232 private Dictionary<uint,OdePrim> _prims = new Dictionary<uint,OdePrim>();
374 /// A dictionary of actors that should receive collision events. 233 private HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
375 /// </summary> 234 private HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
376 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>(); 235 private HashSet<OdePrim> _activegroups = new HashSet<OdePrim>();
377 236
378 /// <summary> 237 public OpenSim.Framework.LocklessQueue<ODEchangeitem> ChangesQueue = new OpenSim.Framework.LocklessQueue<ODEchangeitem>();
379 /// A dictionary of collision event changes that are waiting to be processed.
380 /// </summary>
381 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>();
382 238
383 /// <summary> 239 /// <summary>
384 /// Maps a unique geometry id (a memory location) to a physics actor name. 240 /// A list of actors that should receive collision events.
385 /// </summary> 241 /// </summary>
386 /// <remarks> 242 private List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
387 /// Only actors participating in collisions have geometries. This has to be maintained separately from 243 private List<PhysicsActor> _collisionEventPrimRemove = new List<PhysicsActor>();
388 /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own 244
389 /// apart from the singleton PANull 245 private HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
390 /// </remarks>
391 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
392
393 /// <summary>
394 /// Maps a unique geometry id (a memory location) to a physics actor.
395 /// </summary>
396 /// <remarks>
397 /// Only actors participating in collisions have geometries.
398 /// </remarks>
399 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); 246 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
400 247
401 /// <summary> 248 private float contactsurfacelayer = 0.002f;
402 /// Defects list to remove characters that no longer have finite positions due to some other bug.
403 /// </summary>
404 /// <remarks>
405 /// Used repeatedly in Simulate() but initialized once here.
406 /// </remarks>
407 private readonly List<OdeCharacter> defects = new List<OdeCharacter>();
408 249
409 private bool m_NINJA_physics_joints_enabled = false; 250 private int contactsPerCollision = 80;
410 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>(); 251 internal IntPtr ContactgeomsArray = IntPtr.Zero;
411 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>(); 252 private IntPtr GlobalContactsArray = IntPtr.Zero;
412 private d.ContactGeom[] contacts; 253 private d.Contact SharedTmpcontact = new d.Contact();
413 254
414 /// <summary> 255 const int maxContactsbeforedeath = 6000;
415 /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active 256 private volatile int m_global_contactcount = 0;
416 /// </summary>
417 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>();
418 257
419 /// <summary> 258 private IntPtr contactgroup;
420 /// can lock for longer. accessed only by OdeScene.
421 /// </summary>
422 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>();
423 259
424 /// <summary> 260 public ContactData[] m_materialContactsData = new ContactData[8];
425 /// can lock for longer. accessed only by OdeScene.
426 /// </summary>
427 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>();
428 261
429 /// <summary> 262 private IntPtr TerrainGeom;
430 /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active 263 private float[] TerrainHeightFieldHeight;
431 /// </summary> 264 private GCHandle TerrainHeightFieldHeightsHandler = new GCHandle();
432 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); 265
433 266 private int m_physicsiterations = 15;
434 private Object externalJointRequestsLock = new Object();
435 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
436 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
437 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
438 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
439
440 private d.Contact contact;
441 private d.Contact TerrainContact;
442 private d.Contact AvatarMovementprimContact;
443 private d.Contact AvatarMovementTerrainContact;
444 private d.Contact WaterContact;
445 private d.Contact[,] m_materialContacts;
446
447 private int m_physicsiterations = 10;
448 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag 267 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
449 private readonly PhysicsActor PANull = new NullPhysicsActor(); 268// private PhysicsActor PANull = new NullPhysicsActor();
450 private float step_time = 0.0f; 269 private float step_time = 0.0f;
270
451 public IntPtr world; 271 public IntPtr world;
452 private uint obj2LocalID = 0;
453 private OdeCharacter cc1;
454 private OdePrim cp1;
455 private OdeCharacter cc2;
456 private OdePrim cp2;
457 private int p1ExpectedPoints = 0;
458 private int p2ExpectedPoints = 0;
459 272
460 public IntPtr space; 273 // split the spaces acording to contents type
274 // ActiveSpace contains characters and active prims
275 // StaticSpace contains land and other that is mostly static in enviroment
276 // this can contain subspaces, like the grid in staticspace
277 // as now space only contains this 2 top spaces
461 278
462 // split static geometry collision handling into spaces of 30 meters 279 public IntPtr TopSpace; // the global space
463 public IntPtr[,] staticPrimspace; 280 public IntPtr ActiveSpace; // space for active prims
281 public IntPtr CharsSpace; // space for active prims
282 public IntPtr StaticSpace; // space for the static things around
283 public IntPtr GroundSpace; // space for ground
464 284
465 /// <summary> 285 // some speedup variables
466 /// Used to lock the entire physics scene. Locked during the main part of Simulate() 286 private int spaceGridMaxX;
467 /// </summary> 287 private int spaceGridMaxY;
468 internal Object OdeLock = new Object(); 288 private float spacesPerMeterX;
289 private float spacesPerMeterY;
290
291 // split static geometry collision into a grid as before
292 private IntPtr[,] staticPrimspace;
293 private IntPtr[] staticPrimspaceOffRegion;
469 294
470 private bool _worldInitialized = false; 295 public Object OdeLock;
296 public static Object SimulationLock;
471 297
472 public IMesher mesher; 298 public IMesher mesher;
473 299
474 private IConfigSource m_config; 300 public IConfigSource m_config;
475 301
476 public bool physics_logging = false; 302 public bool physics_logging = false;
477 public int physics_logging_interval = 0; 303 public int physics_logging_interval = 0;
478 public bool physics_logging_append_existing_logfile = false; 304 public bool physics_logging_append_existing_logfile = false;
479 305
480 private bool avplanted = false; 306 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
481 private bool av_av_collisions_off = false;
482 307
483 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); 308 private ODERayCastRequestManager m_rayCastManager;
484 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); 309 public ODEMeshWorker m_meshWorker;
485 310
486 private volatile int m_global_contactcount = 0; 311 /* maybe needed if ode uses tls
312 private void checkThread()
313 {
487 314
488 private Vector3 m_worldOffset = Vector3.Zero; 315 int th = Thread.CurrentThread.ManagedThreadId;
489 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); 316 if(th != threadid)
490 private PhysicsScene m_parentScene = null; 317 {
318 threadid = th;
319 d.AllocateODEDataForThread(~0U);
320 }
321 }
322 */
491 323
492 float spacesPerMeterX; 324 IConfig physicsconfig = null;
493 float spacesPerMeterY;
494 int spaceGridMaxX;
495 int spaceGridMaxY;
496 325
497 private ODERayCastRequestManager m_rayCastManager; 326 public ODEScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion, bool pOSOdeLib)
498 327 {
499 public Scene m_frameWorkScene = null; 328 OdeLock = new Object();
500 329
501 public OdeScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion)
502 {
503 m_config = psourceconfig;
504 m_frameWorkScene = pscene;
505
506 EngineType = pname; 330 EngineType = pname;
507 PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName; 331 PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName;
508 EngineName = pname + " " + pversion; 332 EngineName = pname + " " + pversion;
333 m_config = psourceconfig;
334 m_OSOdeLib = pOSOdeLib;
335
336// m_OSOdeLib = false; //debug
337
338 m_frameWorkScene = pscene;
509 339
510 pscene.RegisterModuleInterface<PhysicsScene>(this); 340 m_frameWorkScene.RegisterModuleInterface<PhysicsScene>(this);
511 Vector3 extent = new Vector3(pscene.RegionInfo.RegionSizeX, pscene.RegionInfo.RegionSizeY, pscene.RegionInfo.RegionSizeZ);
512 Initialise(extent);
513 InitialiseFromConfig(m_config);
514 341
515 // This may not be that good since terrain may not be avaiable at this point 342 Initialization();
516 base.Initialise(pscene.PhysicsRequestAsset,
517 (pscene.Heightmap != null ? pscene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]),
518 (float)pscene.RegionInfo.RegionSettings.WaterHeight);
519 343
344 base.Initialise(m_frameWorkScene.PhysicsRequestAsset,
345 (m_frameWorkScene.Heightmap != null ? m_frameWorkScene.Heightmap.GetFloatsSerialised() : new float[m_frameWorkScene.RegionInfo.RegionSizeX * m_frameWorkScene.RegionInfo.RegionSizeY]),
346 (float)m_frameWorkScene.RegionInfo.RegionSettings.WaterHeight);
520 } 347 }
521 348
522 public void RegionLoaded() 349 public void RegionLoaded()
523 { 350 {
524 mesher = m_frameWorkScene.RequestModuleInterface<IMesher>(); 351 mesher = m_frameWorkScene.RequestModuleInterface<IMesher>();
525 if (mesher == null) 352 if (mesher == null)
526 m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName); 353 {
527 354 m_log.ErrorFormat("[ubOde] No mesher. module disabled");
528 m_frameWorkScene.PhysicsEnabled = true; 355 return;
356 }
357
358 m_meshWorker = new ODEMeshWorker(this, m_log, mesher, physicsconfig);
359 m_frameWorkScene.PhysicsEnabled = true;
529 } 360 }
530
531 /// <summary> 361 /// <summary>
532 /// Initiailizes the scene 362 /// Initiailizes the scene
533 /// Sets many properties that ODE requires to be stable 363 /// Sets many properties that ODE requires to be stable
534 /// These settings need to be tweaked 'exactly' right or weird stuff happens. 364 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
535 /// </summary> 365 /// </summary>
536 private void Initialise(Vector3 regionExtent) 366 private void Initialization()
537 { 367 {
538 WorldExtents.X = regionExtent.X; 368 d.AllocateODEDataForThread(~0U);
539 m_regionWidth = (uint)regionExtent.X; 369
540 WorldExtents.Y = regionExtent.Y; 370 SimulationLock = new Object();
541 m_regionHeight = (uint)regionExtent.Y; 371
542
543 nearCallback = near; 372 nearCallback = near;
373
544 m_rayCastManager = new ODERayCastRequestManager(this); 374 m_rayCastManager = new ODERayCastRequestManager(this);
545 375
546 // Create the world and the first space 376 WorldExtents.X = m_frameWorkScene.RegionInfo.RegionSizeX;
547 world = d.WorldCreate(); 377 m_regionWidth = (uint)WorldExtents.X;
548 space = d.HashSpaceCreate(IntPtr.Zero); 378 WorldExtents.Y = m_frameWorkScene.RegionInfo.RegionSizeY;
379 m_regionHeight = (uint)WorldExtents.Y;
549 380
550 contactgroup = d.JointGroupCreate(0); 381 lock (OdeLock)
382 {
383 // Create the world and the first space
384 try
385 {
386 world = d.WorldCreate();
387 TopSpace = d.HashSpaceCreate(IntPtr.Zero);
551 388
552 d.WorldSetAutoDisableFlag(world, false); 389 // now the major subspaces
553 } 390 ActiveSpace = d.HashSpaceCreate(TopSpace);
391 CharsSpace = d.HashSpaceCreate(TopSpace);
392 StaticSpace = d.HashSpaceCreate(TopSpace);
393 GroundSpace = d.HashSpaceCreate(TopSpace);
394 }
395 catch
396 {
397 // i must RtC#FM
398 // i did!
399 }
554 400
555 // Initialize from configs 401 d.HashSpaceSetLevels(TopSpace, -5, 12);
556 private void InitialiseFromConfig(IConfigSource config) 402 d.HashSpaceSetLevels(ActiveSpace, -5, 10);
557 { 403 d.HashSpaceSetLevels(CharsSpace, -4, 3);
558 InitializeExtraStats(); 404 d.HashSpaceSetLevels(StaticSpace, -5, 12);
405 d.HashSpaceSetLevels(GroundSpace, 0, 8);
559 406
560 m_config = config; 407 // demote to second level
561 // Defaults 408 d.SpaceSetSublevel(ActiveSpace, 1);
409 d.SpaceSetSublevel(CharsSpace, 1);
410 d.SpaceSetSublevel(StaticSpace, 1);
411 d.SpaceSetSublevel(GroundSpace, 1);
412
413 d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space |
414 CollisionCategories.Geom |
415 CollisionCategories.Character |
416 CollisionCategories.Phantom |
417 CollisionCategories.VolumeDtc
418 ));
419 d.GeomSetCollideBits(ActiveSpace, (uint)(CollisionCategories.Space |
420 CollisionCategories.Geom |
421 CollisionCategories.Character |
422 CollisionCategories.Phantom |
423 CollisionCategories.VolumeDtc
424 ));
425 d.GeomSetCategoryBits(CharsSpace, (uint)(CollisionCategories.Space |
426 CollisionCategories.Geom |
427 CollisionCategories.Character |
428 CollisionCategories.Phantom |
429 CollisionCategories.VolumeDtc
430 ));
431 d.GeomSetCollideBits(CharsSpace, 0);
562 432
563 avPIDD = 2200.0f; 433 d.GeomSetCategoryBits(StaticSpace, (uint)(CollisionCategories.Space |
564 avPIDP = 900.0f; 434 CollisionCategories.Geom |
565 avStandupTensor = 550000f; 435 // CollisionCategories.Land |
436 // CollisionCategories.Water |
437 CollisionCategories.Phantom |
438 CollisionCategories.VolumeDtc
439 ));
440 d.GeomSetCollideBits(StaticSpace, 0);
441
442 d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land));
443 d.GeomSetCollideBits(GroundSpace, 0);
444
445 contactgroup = d.JointGroupCreate(maxContactsbeforedeath + 1);
446 //contactgroup
447
448 d.WorldSetAutoDisableFlag(world, false);
449 }
450
451
452 // checkThread();
453
454
455 // Defaults
566 456
567 int contactsPerCollision = 80; 457 int contactsPerCollision = 80;
568 458
459 physicsconfig = null;
460
569 if (m_config != null) 461 if (m_config != null)
570 { 462 {
571 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; 463 physicsconfig = m_config.Configs["ODEPhysicsSettings"];
572 if (physicsconfig != null) 464 if (physicsconfig != null)
573 { 465 {
574 CollectStats = physicsconfig.GetBoolean("collect_stats", false); 466 gravityx = physicsconfig.GetFloat("world_gravityx", gravityx);
467 gravityy = physicsconfig.GetFloat("world_gravityy", gravityy);
468 gravityz = physicsconfig.GetFloat("world_gravityz", gravityz);
575 469
576 gravityx = physicsconfig.GetFloat("world_gravityx", 0f); 470 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", metersInSpace);
577 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
578 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
579 471
580 float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); 472 // contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", contactsurfacelayer);
581 AvatarTerminalVelocity = Util.Clamp<float>(avatarTerminalVelocity, 0, 255f);
582 if (AvatarTerminalVelocity != avatarTerminalVelocity)
583 {
584 m_log.WarnFormat(
585 "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}",
586 avatarTerminalVelocity, AvatarTerminalVelocity);
587 }
588 473
589 HashspaceLow = physicsconfig.GetInt("world_hashspace_level_low", -5); 474 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
590 HashspaceHigh = physicsconfig.GetInt("world_hashspace_level_high", 12);
591 475
592 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); 476 avDensity = physicsconfig.GetFloat("av_density", avDensity);
477 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", avMovementDivisorWalk);
478 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", avMovementDivisorRun);
593 479
594 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); 480 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", contactsPerCollision);
595 481
596 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); 482 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity);
597 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); 483 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable);
598 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
599 484
600 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); 485 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
601 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); 486 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
602 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); 487 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
603 488
604 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); 489 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", minimumGroundFlightOffset);
605 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); 490 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", maximumMassObject);
606 491
607 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); 492 avDensity *= 3f / 80f; // scale other engines density option to this
608 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); 493 }
494 }
609 495
610 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); 496 float heartbeat = 1/m_frameWorkScene.FrameTime;
611 m_physicsiterations = physicsconfig.GetInt("world_solver_iterations", 10); 497 maximumAngularVelocity = 0.49f * heartbeat *(float)Math.PI;
498 maxAngVelocitySQ = maximumAngularVelocity * maximumAngularVelocity;
612 499
613 avDensity = physicsconfig.GetFloat("av_density", 80f); 500 d.WorldSetCFM(world, comumContactCFM);
614// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); 501 d.WorldSetERP(world, comumContactERP);
615 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
616 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
617 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
618 avplanted = physicsconfig.GetBoolean("av_planted", false);
619 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
620 502
621 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); 503 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
622 504
623 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); 505 d.WorldSetLinearDamping(world, 0.002f);
506 d.WorldSetAngularDamping(world, 0.002f);
507 d.WorldSetAngularDampingThreshold(world, 0f);
508 d.WorldSetLinearDampingThreshold(world, 0f);
509 d.WorldSetMaxAngularSpeed(world, maximumAngularVelocity);
624 510
625 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); 511 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
626 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
627 512
628 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); 513 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
629 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); 514 d.WorldSetContactMaxCorrectingVel(world, 60.0f);
630 515
631 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); 516 HalfOdeStep = ODE_STEPSIZE * 0.5f;
632 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); 517 odetimestepMS = (int)(1000.0f * ODE_STEPSIZE + 0.5f);
633 518
634 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); 519 ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf);
635 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); 520 GlobalContactsArray = Marshal.AllocHGlobal((maxContactsbeforedeath + 100) * d.Contact.unmanagedSizeOf);
636 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
637 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
638 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
639 521
640 avPIDD = physicsconfig.GetFloat("av_pid_derivative", 2200.0f); 522 SharedTmpcontact.geom.g1 = IntPtr.Zero;
641 avPIDP = physicsconfig.GetFloat("av_pid_proportional", 900.0f); 523 SharedTmpcontact.geom.g2 = IntPtr.Zero;
642 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor", 550000f);
643 524
644 physics_logging = physicsconfig.GetBoolean("physics_logging", false); 525 SharedTmpcontact.geom.side1 = -1;
645 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); 526 SharedTmpcontact.geom.side2 = -1;
646 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
647 527
648// m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); 528 SharedTmpcontact.surface.mode = comumContactFlags;
649 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); 529 SharedTmpcontact.surface.mu = 0;
650 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); 530 SharedTmpcontact.surface.bounce = 0;
651 } 531 SharedTmpcontact.surface.soft_cfm = comumContactCFM;
652 } 532 SharedTmpcontact.surface.soft_erp = comumContactERP;
533 SharedTmpcontact.surface.slip1 = comumContactSLIP;
534 SharedTmpcontact.surface.slip2 = comumContactSLIP;
653 535
654 contacts = new d.ContactGeom[contactsPerCollision]; 536 m_materialContactsData[(int)Material.Stone].mu = 0.8f;
537 m_materialContactsData[(int)Material.Stone].bounce = 0.4f;
655 538
656 spacesPerMeterX = 1.0f / metersInSpace; 539 m_materialContactsData[(int)Material.Metal].mu = 0.3f;
657 spacesPerMeterY = 1.0f / metersInSpace; 540 m_materialContactsData[(int)Material.Metal].bounce = 0.4f;
541
542 m_materialContactsData[(int)Material.Glass].mu = 0.2f;
543 m_materialContactsData[(int)Material.Glass].bounce = 0.7f;
658 544
545 m_materialContactsData[(int)Material.Wood].mu = 0.6f;
546 m_materialContactsData[(int)Material.Wood].bounce = 0.5f;
547
548 m_materialContactsData[(int)Material.Flesh].mu = 0.9f;
549 m_materialContactsData[(int)Material.Flesh].bounce = 0.3f;
550
551 m_materialContactsData[(int)Material.Plastic].mu = 0.4f;
552 m_materialContactsData[(int)Material.Plastic].bounce = 0.7f;
553
554 m_materialContactsData[(int)Material.Rubber].mu = 0.9f;
555 m_materialContactsData[(int)Material.Rubber].bounce = 0.95f;
556
557 m_materialContactsData[(int)Material.light].mu = 0.0f;
558 m_materialContactsData[(int)Material.light].bounce = 0.0f;
559
560
561 spacesPerMeterX = 1.0f / metersInSpace;
562 spacesPerMeterY = spacesPerMeterX;
659 spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX); 563 spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX);
660 spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY); 564 spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY);
661 565
662 // note: limit number of spaces
663 if (spaceGridMaxX > 24) 566 if (spaceGridMaxX > 24)
664 { 567 {
665 spaceGridMaxX = 24; 568 spaceGridMaxX = 24;
666 spacesPerMeterX = spaceGridMaxX / WorldExtents.X; 569 spacesPerMeterX = spaceGridMaxX / WorldExtents.X;
667 } 570 }
571
668 if (spaceGridMaxY > 24) 572 if (spaceGridMaxY > 24)
669 { 573 {
670 spaceGridMaxY = 24; 574 spaceGridMaxY = 24;
671 spacesPerMeterY = spaceGridMaxY / WorldExtents.Y; 575 spacesPerMeterY = spaceGridMaxY / WorldExtents.Y;
672 } 576 }
673 577
674 staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; 578 staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY];
675
676 // make this index limits
677 spaceGridMaxX--;
678 spaceGridMaxY--;
679
680 // Centeral contact friction and bounce
681 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
682 // an avatar falls through in Z but not in X or Y when walking on a prim.
683 contact.surface.mode |= d.ContactFlags.SoftERP;
684 contact.surface.mu = nmAvatarObjectContactFriction;
685 contact.surface.bounce = nmAvatarObjectContactBounce;
686 contact.surface.soft_cfm = 0.010f;
687 contact.surface.soft_erp = 0.010f;
688
689 // Terrain contact friction and Bounce
690 // This is the *non* moving version. Use this when an avatar
691 // isn't moving to keep it in place better
692 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
693 TerrainContact.surface.mu = nmTerrainContactFriction;
694 TerrainContact.surface.bounce = nmTerrainContactBounce;
695 TerrainContact.surface.soft_erp = nmTerrainContactERP;
696
697 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
698 WaterContact.surface.mu = 0f; // No friction
699 WaterContact.surface.bounce = 0.0f; // No bounce
700 WaterContact.surface.soft_cfm = 0.010f;
701 WaterContact.surface.soft_erp = 0.010f;
702
703 // Prim contact friction and bounce
704 // THis is the *non* moving version of friction and bounce
705 // Use this when an avatar comes in contact with a prim
706 // and is moving
707 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
708 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
709
710 // Terrain contact friction bounce and various error correcting calculations
711 // Use this when an avatar is in contact with the terrain and moving.
712 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
713 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
714 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
715 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
716 579
717 /* 580 // create all spaces now
718 <summary></summary> 581 int i, j;
719 Stone = 0, 582 IntPtr newspace;
720 /// <summary></summary>
721 Metal = 1,
722 /// <summary></summary>
723 Glass = 2,
724 /// <summary></summary>
725 Wood = 3,
726 /// <summary></summary>
727 Flesh = 4,
728 /// <summary></summary>
729 Plastic = 5,
730 /// <summary></summary>
731 Rubber = 6
732 */
733
734 m_materialContacts = new d.Contact[7,2];
735
736 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
737 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
738 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
739 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
740 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
741 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
742
743 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
744 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
745 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
746 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
747 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
748 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
749
750 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
751 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
752 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
753 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
754 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
755 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
756
757 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
758 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
759 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
760 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
761 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
762 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
763
764 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
765 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
766 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
767 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
768 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
769 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
770 583
771 /* 584 for (i = 0; i < spaceGridMaxX; i++)
772 private float nmAvatarObjectContactFriction = 250f; 585 for (j = 0; j < spaceGridMaxY; j++)
773 private float nmAvatarObjectContactBounce = 0.1f; 586 {
587 newspace = d.HashSpaceCreate(StaticSpace);
588 d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space);
589 waitForSpaceUnlock(newspace);
590 d.SpaceSetSublevel(newspace, 2);
591 d.HashSpaceSetLevels(newspace, -2, 8);
592 d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space |
593 CollisionCategories.Geom |
594 CollisionCategories.Land |
595 CollisionCategories.Water |
596 CollisionCategories.Phantom |
597 CollisionCategories.VolumeDtc
598 ));
599 d.GeomSetCollideBits(newspace, 0);
774 600
775 private float mAvatarObjectContactFriction = 75f; 601 staticPrimspace[i, j] = newspace;
776 private float mAvatarObjectContactBounce = 0.1f; 602 }
777 */
778 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
779 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
780 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
781 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
782 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
783 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
784
785 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
786 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
787 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
788 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
789 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
790 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
791
792 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
793 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
794 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
795 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
796 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
797 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
798
799 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
800 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
801 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
802 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
803 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
804 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
805
806 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
807 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
808 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
809 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
810 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
811 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
812
813 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
814 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
815 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
816 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
817 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
818 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
819
820 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
821 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
822 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
823 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
824 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
825 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
826
827 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
828 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
829 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
830 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
831 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
832 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
833
834 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
835 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
836 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
837 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
838 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
839 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
840
841 d.HashSpaceSetLevels(space, HashspaceLow, HashspaceHigh);
842
843 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
844 603
845 d.WorldSetGravity(world, gravityx, gravityy, gravityz); 604 // let this now be index limit
846 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); 605 spaceGridMaxX--;
606 spaceGridMaxY--;
847 607
848 d.WorldSetLinearDamping(world, 256f); 608 // create 4 off world spaces (x<0,x>max,y<0,y>max)
849 d.WorldSetAngularDamping(world, 256f); 609 staticPrimspaceOffRegion = new IntPtr[4];
850 d.WorldSetAngularDampingThreshold(world, 256f);
851 d.WorldSetLinearDampingThreshold(world, 256f);
852 d.WorldSetMaxAngularSpeed(world, 256f);
853 610
854 d.WorldSetQuickStepNumIterations(world, m_physicsiterations); 611 for (i = 0; i < 4; i++)
855 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
856
857 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
858 { 612 {
859 for (int j = 0; j < staticPrimspace.GetLength(1); j++) 613 newspace = d.HashSpaceCreate(StaticSpace);
860 { 614 d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space);
861 staticPrimspace[i, j] = IntPtr.Zero; 615 waitForSpaceUnlock(newspace);
862 } 616 d.SpaceSetSublevel(newspace, 2);
617 d.HashSpaceSetLevels(newspace, -2, 8);
618 d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space |
619 CollisionCategories.Geom |
620 CollisionCategories.Land |
621 CollisionCategories.Water |
622 CollisionCategories.Phantom |
623 CollisionCategories.VolumeDtc
624 ));
625 d.GeomSetCollideBits(newspace, 0);
626
627 staticPrimspaceOffRegion[i] = newspace;
863 } 628 }
864 629
865 _worldInitialized = true; 630 m_lastframe = DateTime.UtcNow;
631 m_lastMeshExpire = m_lastframe;
866 } 632 }
867 633
868 #region Collision Detection 634 internal void waitForSpaceUnlock(IntPtr space)
869
870 /// <summary>
871 /// Collides two geometries.
872 /// </summary>
873 /// <returns></returns>
874 /// <param name='geom1'></param>
875 /// <param name='geom2'>/param>
876 /// <param name='maxContacts'></param>
877 /// <param name='contactsArray'></param>
878 /// <param name='contactGeomSize'></param>
879 private int CollideGeoms(
880 IntPtr geom1, IntPtr geom2, int maxContacts, d.ContactGeom[] contactsArray, int contactGeomSize)
881 { 635 {
882 int count; 636 //if (space != IntPtr.Zero)
637 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
638 }
883 639
884 lock (OdeScene.UniversalColliderSyncObject) 640 #region Collision Detection
885 {
886 // We do this inside the lock so that we don't count any delay in acquiring it
887 if (CollectStats)
888 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
889 641
890 count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); 642 // sets a global contact for a joint for contactgeom , and base contact description)
891 } 643 private IntPtr CreateContacJoint(ref d.ContactGeom contactGeom,bool smooth)
644 {
645 if (m_global_contactcount >= maxContactsbeforedeath)
646 return IntPtr.Zero;
892 647
893 // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably 648 m_global_contactcount++;
894 // negligable 649 if(smooth)
895 if (CollectStats) 650 SharedTmpcontact.geom.depth = contactGeom.depth * 0.05f;
896 m_stats[ODENativeGeomCollisionFrameMsStatName] 651 else
897 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); 652 SharedTmpcontact.geom.depth = contactGeom.depth;
653 SharedTmpcontact.geom.pos = contactGeom.pos;
654 SharedTmpcontact.geom.normal = contactGeom.normal;
898 655
899 return count; 656 IntPtr contact = new IntPtr(GlobalContactsArray.ToInt64() + (Int64)(m_global_contactcount * d.Contact.unmanagedSizeOf));
657 Marshal.StructureToPtr(SharedTmpcontact, contact, true);
658 return d.JointCreateContactPtr(world, contactgroup, contact);
900 } 659 }
901 660
902 /// <summary> 661 private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
903 /// Collide two spaces or a space and a geometry.
904 /// </summary>
905 /// <param name='space1'></param>
906 /// <param name='space2'>/param>
907 /// <param name='data'></param>
908 private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
909 { 662 {
910 if (CollectStats) 663 if (ContactgeomsArray == IntPtr.Zero || index >= contactsPerCollision)
911 { 664 return false;
912 m_inCollisionTiming = true;
913 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
914 }
915
916 d.SpaceCollide2(space1, space2, data, nearCallback);
917 665
918 if (CollectStats && m_inCollisionTiming) 666 IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
919 { 667 newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
920 m_stats[ODENativeSpaceCollisionFrameMsStatName] 668 return true;
921 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
922 m_inCollisionTiming = false;
923 }
924 } 669 }
925 670
926 /// <summary> 671 /// <summary>
@@ -929,70 +674,50 @@ namespace OpenSim.Region.PhysicsModule.ODE
929 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param> 674 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
930 /// <param name="g1">a geometry or space</param> 675 /// <param name="g1">a geometry or space</param>
931 /// <param name="g2">another geometry or space</param> 676 /// <param name="g2">another geometry or space</param>
677 ///
678
932 private void near(IntPtr space, IntPtr g1, IntPtr g2) 679 private void near(IntPtr space, IntPtr g1, IntPtr g2)
933 { 680 {
934 if (CollectStats && m_inCollisionTiming)
935 {
936 m_stats[ODENativeSpaceCollisionFrameMsStatName]
937 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
938 m_inCollisionTiming = false;
939 }
940
941// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
942 // no lock here! It's invoked from within Simulate(), which is thread-locked 681 // no lock here! It's invoked from within Simulate(), which is thread-locked
943 682
683 if (m_global_contactcount >= maxContactsbeforedeath)
684 return;
685
944 // Test if we're colliding a geom with a space. 686 // Test if we're colliding a geom with a space.
945 // If so we have to drill down into the space recursively 687 // If so we have to drill down into the space recursively
946 688
689 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
690 return;
691
947 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) 692 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
948 { 693 {
949 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
950 return;
951
952 // Separating static prim geometry spaces.
953 // We'll be calling near recursivly if one 694 // We'll be calling near recursivly if one
954 // of them is a space to find all of the 695 // of them is a space to find all of the
955 // contact points in the space 696 // contact points in the space
956 try 697 try
957 { 698 {
958 CollideSpaces(g1, g2, IntPtr.Zero); 699 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
959 } 700 }
960 catch (AccessViolationException) 701 catch (AccessViolationException)
961 { 702 {
962 m_log.Error("[ODE SCENE]: Unable to collide test a space"); 703 m_log.Warn("[PHYSICS]: Unable to collide test a space");
963 return; 704 return;
964 } 705 }
965 //Colliding a space or a geom with a space or a geom. so drill down 706 //here one should check collisions of geoms inside a space
966 707 // but on each space we only should have geoms that not colide amoung each other
967 //Collide all geoms in each space.. 708 // so we don't dig inside spaces
968 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
969 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
970 return; 709 return;
971 } 710 }
972 711
973 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) 712 // get geom bodies to check if we already a joint contact
974 return; 713 // guess this shouldn't happen now
975
976 IntPtr b1 = d.GeomGetBody(g1); 714 IntPtr b1 = d.GeomGetBody(g1);
977 IntPtr b2 = d.GeomGetBody(g2); 715 IntPtr b2 = d.GeomGetBody(g2);
978 716
979 // d.GeomClassID id = d.GeomGetClass(g1); 717 // d.GeomClassID id = d.GeomGetClass(g1);
980 718
981 String name1 = null;
982 String name2 = null;
983
984 if (!geom_name_map.TryGetValue(g1, out name1))
985 {
986 name1 = "null";
987 }
988 if (!geom_name_map.TryGetValue(g2, out name2))
989 {
990 name2 = "null";
991 }
992
993 // Figure out how many contact points we have 719 // Figure out how many contact points we have
994 int count = 0; 720 int count = 0;
995
996 try 721 try
997 { 722 {
998 // Colliding Geom To Geom 723 // Colliding Geom To Geom
@@ -1003,444 +728,329 @@ namespace OpenSim.Region.PhysicsModule.ODE
1003 728
1004 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) 729 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
1005 return; 730 return;
731 /*
732 // debug
733 PhysicsActor dp2;
734 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
735 {
736 d.AABB aabb;
737 d.GeomGetAABB(g2, out aabb);
738 float x = aabb.MaxX - aabb.MinX;
739 float y = aabb.MaxY - aabb.MinY;
740 float z = aabb.MaxZ - aabb.MinZ;
741 if (x > 60.0f || y > 60.0f || z > 60.0f)
742 {
743 if (!actor_name_map.TryGetValue(g2, out dp2))
744 m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
745 else
746 m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})",
747 dp2.Name, dp2.Size, x, y, z,
748 dp2.Position.ToString(),
749 dp2.Orientation.ToString(),
750 dp2.Orientation.Length());
751 return;
752 }
753 }
754 //
755 */
1006 756
1007 count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.unmanagedSizeOf);
1008
1009 // All code after this is only relevant if we have any collisions
1010 if (count <= 0)
1011 return;
1012 757
1013 if (count > contacts.Length) 758 if (d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc ||
1014 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); 759 d.GeomGetCategoryBits(g2) == (uint)CollisionCategories.VolumeDtc)
760 {
761 int cflags;
762 unchecked
763 {
764 cflags = (int)(1 | d.CONTACTS_UNIMPORTANT);
765 }
766 count = d.CollidePtr(g1, g2, cflags, ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
767 }
768 else
769 count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
1015 } 770 }
1016 catch (SEHException) 771 catch (SEHException)
1017 { 772 {
1018 m_log.Error( 773 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
1019 "[ODE SCENE]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); 774 // ode.drelease(world);
1020 base.TriggerPhysicsBasedRestart(); 775 base.TriggerPhysicsBasedRestart();
1021 } 776 }
1022 catch (Exception e) 777 catch (Exception e)
1023 { 778 {
1024 m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); 779 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
1025 return; 780 return;
1026 } 781 }
1027 782
783 // contacts done
784 if (count == 0)
785 return;
786
787 // try get physical actors
1028 PhysicsActor p1; 788 PhysicsActor p1;
1029 PhysicsActor p2; 789 PhysicsActor p2;
1030 790
1031 p1ExpectedPoints = 0;
1032 p2ExpectedPoints = 0;
1033
1034 if (!actor_name_map.TryGetValue(g1, out p1)) 791 if (!actor_name_map.TryGetValue(g1, out p1))
1035 { 792 {
1036 p1 = PANull; 793 m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 1");
794 return;
1037 } 795 }
1038 796
1039 if (!actor_name_map.TryGetValue(g2, out p2)) 797 if (!actor_name_map.TryGetValue(g2, out p2))
1040 { 798 {
1041 p2 = PANull; 799 m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
800 return;
1042 } 801 }
1043 802
1044 ContactPoint maxDepthContact = new ContactPoint();
1045 if (p1.CollisionScore + count >= float.MaxValue)
1046 p1.CollisionScore = 0;
1047 p1.CollisionScore += count;
1048 803
1049 if (p2.CollisionScore + count >= float.MaxValue) 804 // get first contact
1050 p2.CollisionScore = 0; 805 d.ContactGeom curContact = new d.ContactGeom();
1051 p2.CollisionScore += count;
1052 806
1053 for (int i = 0; i < count; i++) 807 if (!GetCurContactGeom(0, ref curContact))
1054 { 808 return;
1055 d.ContactGeom curContact = contacts[i];
1056 809
1057 if (curContact.depth > maxDepthContact.PenetrationDepth) 810 ContactPoint maxDepthContact = new ContactPoint();
1058 {
1059 maxDepthContact = new ContactPoint(
1060 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1061 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1062 curContact.depth
1063 );
1064 }
1065 811
1066 //m_log.Warn("[CCOUNT]: " + count); 812 // do volume detection case
1067 IntPtr joint; 813 if ((p1.IsVolumeDtc || p2.IsVolumeDtc))
1068 // If we're colliding with terrain, use 'TerrainContact' instead of contact. 814 {
1069 // allows us to have different settings 815 maxDepthContact = new ContactPoint(
1070 816 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1071 // We only need to test p2 for 'jump crouch purposes' 817 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1072 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) 818 curContact.depth, false
1073 { 819 );
1074 // Testing if the collision is at the feet of the avatar
1075 820
1076 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); 821 collision_accounting_events(p1, p2, maxDepthContact);
1077 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) 822 return;
1078 p2.IsColliding = true; 823 }
1079 }
1080 else
1081 {
1082 p2.IsColliding = true;
1083 }
1084
1085 //if ((framecount % m_returncollisions) == 0)
1086 824
1087 switch (p1.PhysicsActorType) 825 // big messy collision analises
1088 {
1089 case (int)ActorTypes.Agent:
1090 p1ExpectedPoints = avatarExpectedContacts;
1091 p2.CollidingObj = true;
1092 break;
1093 case (int)ActorTypes.Prim:
1094 if (p1 != null && p1 is OdePrim)
1095 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1096 826
1097 if (p2.Velocity.LengthSquared() > 0.0f) 827 float mu = 0;
1098 p2.CollidingObj = true; 828 float bounce = 0;
1099 break; 829// bool IgnoreNegSides = false;
1100 case (int)ActorTypes.Unknown:
1101 p2.CollidingGround = true;
1102 break;
1103 default:
1104 p2.CollidingGround = true;
1105 break;
1106 }
1107 830
1108 // we don't want prim or avatar to explode 831 ContactData contactdata1 = new ContactData(0, 0, false);
832 ContactData contactdata2 = new ContactData(0, 0, false);
1109 833
1110 #region InterPenetration Handling - Unintended physics explosions 834 bool dop1ava = false;
835 bool dop2ava = false;
836 bool ignore = false;
837 bool smoothMesh = false;
1111 838
1112 if (curContact.depth >= 0.08f) 839 switch (p1.PhysicsActorType)
1113 { 840 {
1114 if (curContact.depth >= 1.00f) 841 case (int)ActorTypes.Agent:
1115 { 842 {
1116 //m_log.Info("[P]: " + contact.depth.ToString()); 843 dop1ava = true;
1117 if ((p2.PhysicsActorType == (int) ActorTypes.Agent && 844 switch (p2.PhysicsActorType)
1118 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
1119 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1120 p2.PhysicsActorType == (int) ActorTypes.Unknown))
1121 { 845 {
1122 if (p2.PhysicsActorType == (int) ActorTypes.Agent) 846 case (int)ActorTypes.Agent:
1123 { 847 case (int)ActorTypes.Prim:
1124 if (p2 is OdeCharacter) 848 break;
1125 {
1126 OdeCharacter character = (OdeCharacter) p2;
1127
1128 //p2.CollidingObj = true;
1129 curContact.depth = 0.00000003f;
1130 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
1131 curContact.pos =
1132 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1133 curContact.pos.Y + (p1.Size.Y/2),
1134 curContact.pos.Z + (p1.Size.Z/2));
1135 character.SetPidStatus(true);
1136 }
1137 }
1138 849
1139 if (p1.PhysicsActorType == (int) ActorTypes.Agent) 850 default:
1140 { 851 ignore = true; // avatar to terrain and water ignored
1141 if (p1 is OdeCharacter) 852 break;
1142 {
1143 OdeCharacter character = (OdeCharacter) p1;
1144
1145 //p2.CollidingObj = true;
1146 curContact.depth = 0.00000003f;
1147 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1148 curContact.pos =
1149 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1150 curContact.pos.Y + (p1.Size.Y/2),
1151 curContact.pos.Z + (p1.Size.Z/2));
1152 character.SetPidStatus(true);
1153 }
1154 }
1155 } 853 }
854 break;
1156 } 855 }
1157 }
1158
1159 #endregion
1160 856
1161 // Logic for collision handling 857 case (int)ActorTypes.Prim:
1162 // Note, that if *all* contacts are skipped (VolumeDetect) 858 {
1163 // The prim still detects (and forwards) collision events but 859 switch (p2.PhysicsActorType)
1164 // appears to be phantom for the world 860 {
1165 Boolean skipThisContact = false; 861 case (int)ActorTypes.Agent:
862 dop2ava = true;
863 break;
1166 864
1167 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) 865 case (int)ActorTypes.Prim:
1168 skipThisContact = true; // No collision on volume detect prims 866 Vector3 relV = p1.rootVelocity - p2.rootVelocity;
867 float relVlenSQ = relV.LengthSquared();
868 if (relVlenSQ > 0.0001f)
869 {
870 p1.CollidingObj = true;
871 p2.CollidingObj = true;
872 }
873 p1.getContactData(ref contactdata1);
874 p2.getContactData(ref contactdata2);
875 bounce = contactdata1.bounce * contactdata2.bounce;
876 mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);
1169 877
1170 if (av_av_collisions_off) 878 if (relVlenSQ > 0.01f)
1171 if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) 879 mu *= frictionMovementMult;
1172 skipThisContact = true;
1173 880
1174 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) 881 if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass &&
1175 skipThisContact = true; // No collision on volume detect prims 882 d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
883 smoothMesh = true;
884 break;
1176 885
1177 if (!skipThisContact && curContact.depth < 0f) 886 case (int)ActorTypes.Ground:
1178 skipThisContact = true; 887 p1.getContactData(ref contactdata1);
888 bounce = contactdata1.bounce * TerrainBounce;
889 mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction);
1179 890
1180 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) 891 Vector3 v1 = p1.rootVelocity;
1181 skipThisContact = true; 892 if (Math.Abs(v1.X) > 0.1f || Math.Abs(v1.Y) > 0.1f)
893 mu *= frictionMovementMult;
894 p1.CollidingGround = true;
1182 895
1183 const int maxContactsbeforedeath = 4000; 896 if(d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
1184 joint = IntPtr.Zero; 897 smoothMesh = true;
898 break;
1185 899
1186 if (!skipThisContact) 900 case (int)ActorTypes.Water:
1187 { 901 default:
1188 _perloopContact.Add(curContact); 902 ignore = true;
903 break;
904 }
905 }
906 break;
1189 907
1190 if (name1 == "Terrain" || name2 == "Terrain") 908 case (int)ActorTypes.Ground:
909 if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1191 { 910 {
1192 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && 911 p2.CollidingGround = true;
1193 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) 912 p2.getContactData(ref contactdata2);
1194 { 913 bounce = contactdata2.bounce * TerrainBounce;
1195 p2ExpectedPoints = avatarExpectedContacts; 914 mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction);
1196 // Avatar is moving on terrain, use the movement terrain contact 915
1197 AvatarMovementTerrainContact.geom = curContact; 916// if (curContact.side1 > 0) // should be 2 ?
1198 917// IgnoreNegSides = true;
1199 if (m_global_contactcount < maxContactsbeforedeath) 918 Vector3 v2 = p2.rootVelocity;
1200 { 919 if (Math.Abs(v2.X) > 0.1f || Math.Abs(v2.Y) > 0.1f)
1201 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); 920 mu *= frictionMovementMult;
1202 m_global_contactcount++; 921
1203 } 922 if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass)
1204 } 923 smoothMesh = true;
1205 else 924 }
1206 { 925 else
1207 if (p2.PhysicsActorType == (int)ActorTypes.Agent) 926 ignore = true;
1208 { 927 break;
1209 p2ExpectedPoints = avatarExpectedContacts;
1210 // Avatar is standing on terrain, use the non moving terrain contact
1211 TerrainContact.geom = curContact;
1212 928
1213 if (m_global_contactcount < maxContactsbeforedeath) 929 case (int)ActorTypes.Water:
1214 { 930 default:
1215 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); 931 break;
1216 m_global_contactcount++; 932 }
1217 }
1218 }
1219 else
1220 {
1221 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1222 {
1223 // prim prim contact
1224 // int pj294950 = 0;
1225 int movintYN = 0;
1226 int material = (int) Material.Wood;
1227 // prim terrain contact
1228 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1229 {
1230 movintYN = 1;
1231 }
1232 933
1233 if (p2 is OdePrim) 934 if (ignore)
1234 { 935 return;
1235 material = ((OdePrim) p2).m_material;
1236 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1237 }
1238
1239 // Unnessesary because p1 is defined above
1240 //if (p1 is OdePrim)
1241 // {
1242 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1243 // }
1244 //m_log.DebugFormat("Material: {0}", material);
1245 936
1246 m_materialContacts[material, movintYN].geom = curContact; 937 IntPtr Joint;
938 bool FeetCollision = false;
939 int ncontacts = 0;
1247 940
1248 if (m_global_contactcount < maxContactsbeforedeath) 941 int i = 0;
1249 {
1250 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1251 m_global_contactcount++;
1252 }
1253 }
1254 else
1255 {
1256 int movintYN = 0;
1257 // prim terrain contact
1258 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1259 {
1260 movintYN = 1;
1261 }
1262 942
1263 int material = (int)Material.Wood; 943 maxDepthContact = new ContactPoint();
944 maxDepthContact.PenetrationDepth = float.MinValue;
945 ContactPoint minDepthContact = new ContactPoint();
946 minDepthContact.PenetrationDepth = float.MaxValue;
1264 947
1265 if (p2 is OdePrim) 948 SharedTmpcontact.geom.depth = 0;
1266 { 949 SharedTmpcontact.surface.mu = mu;
1267 material = ((OdePrim)p2).m_material; 950 SharedTmpcontact.surface.bounce = bounce;
1268 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1269 }
1270 951
1271 //m_log.DebugFormat("Material: {0}", material); 952 d.ContactGeom altContact = new d.ContactGeom();
1272 m_materialContacts[material, movintYN].geom = curContact; 953 bool useAltcontact = false;
954 bool noskip = true;
1273 955
1274 if (m_global_contactcount < maxContactsbeforedeath) 956 if(dop1ava || dop2ava)
1275 { 957 smoothMesh = false;
1276 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1277 m_global_contactcount++;
1278 }
1279 }
1280 }
1281 }
1282 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1283 //{
1284 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1285 //}
1286 }
1287 else if (name1 == "Water" || name2 == "Water")
1288 {
1289 /*
1290 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1291 {
1292 }
1293 else
1294 {
1295 }
1296 */
1297 //WaterContact.surface.soft_cfm = 0.0000f;
1298 //WaterContact.surface.soft_erp = 0.00000f;
1299 if (curContact.depth > 0.1f)
1300 {
1301 curContact.depth *= 52;
1302 //contact.normal = new d.Vector3(0, 0, 1);
1303 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1304 }
1305 958
1306 WaterContact.geom = curContact; 959 while (true)
960 {
961 noskip = true;
962 useAltcontact = false;
1307 963
1308 if (m_global_contactcount < maxContactsbeforedeath) 964 if (dop1ava)
965 {
966 if ((((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
967 {
968 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1309 { 969 {
1310 joint = d.JointCreateContact(world, contactgroup, ref WaterContact); 970 p1.CollidingObj = true;
1311 m_global_contactcount++; 971 p2.CollidingObj = true;
1312 } 972 }
1313 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); 973 else if (p2.rootVelocity.LengthSquared() > 0.0f)
974 p2.CollidingObj = true;
1314 } 975 }
1315 else 976 else
977 noskip = false;
978 }
979 else if (dop2ava)
980 {
981 if ((((OdeCharacter)p2).Collide(g2, g1, true, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
1316 { 982 {
1317 if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) 983 if (p1.PhysicsActorType == (int)ActorTypes.Agent)
1318 { 984 {
1319 p2ExpectedPoints = avatarExpectedContacts; 985 p1.CollidingObj = true;
1320 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) 986 p2.CollidingObj = true;
1321 {
1322 // Avatar is moving on a prim, use the Movement prim contact
1323 AvatarMovementprimContact.geom = curContact;
1324
1325 if (m_global_contactcount < maxContactsbeforedeath)
1326 {
1327 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1328 m_global_contactcount++;
1329 }
1330 }
1331 else
1332 {
1333 // Avatar is standing still on a prim, use the non movement contact
1334 contact.geom = curContact;
1335
1336 if (m_global_contactcount < maxContactsbeforedeath)
1337 {
1338 joint = d.JointCreateContact(world, contactgroup, ref contact);
1339 m_global_contactcount++;
1340 }
1341 }
1342 }
1343 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1344 {
1345 //p1.PhysicsActorType
1346 int material = (int)Material.Wood;
1347
1348 if (p2 is OdePrim)
1349 {
1350 material = ((OdePrim)p2).m_material;
1351 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1352 }
1353
1354 //m_log.DebugFormat("Material: {0}", material);
1355 m_materialContacts[material, 0].geom = curContact;
1356
1357 if (m_global_contactcount < maxContactsbeforedeath)
1358 {
1359 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1360 m_global_contactcount++;
1361 }
1362 } 987 }
988 else if (p1.rootVelocity.LengthSquared() > 0.0f)
989 p1.CollidingObj = true;
1363 } 990 }
1364 991 else
1365 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! 992 noskip = false;
1366 {
1367 d.JointAttach(joint, b1, b2);
1368 m_global_contactcount++;
1369 }
1370 } 993 }
1371 994
1372 collision_accounting_events(p1, p2, maxDepthContact); 995 if (noskip)
1373
1374 if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1375 { 996 {
1376 // If there are more then 3 contact points, it's likely 997 if(useAltcontact)
1377 // that we've got a pile of objects, so ... 998 Joint = CreateContacJoint(ref altContact,smoothMesh);
1378 // We don't want to send out hundreds of terse updates over and over again 999 else
1379 // so lets throttle them and send them again after it's somewhat sorted out. 1000 Joint = CreateContacJoint(ref curContact,smoothMesh);
1380 p2.ThrottleUpdates = true;
1381 }
1382 //m_log.Debug(count.ToString());
1383 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1384 }
1385 }
1386 1001
1387 private bool checkDupe(d.ContactGeom contactGeom, int atype) 1002 if (Joint == IntPtr.Zero)
1388 { 1003 break;
1389 if (!m_filterCollisions)
1390 return false;
1391 1004
1392 bool result = false; 1005 d.JointAttach(Joint, b1, b2);
1393 1006
1394 ActorTypes at = (ActorTypes)atype; 1007 ncontacts++;
1395 1008
1396 foreach (d.ContactGeom contact in _perloopContact) 1009 if (curContact.depth > maxDepthContact.PenetrationDepth)
1397 {
1398 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1399 //{
1400 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1401 if (at == ActorTypes.Agent)
1402 {
1403 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
1404 && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
1405 && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1406 { 1010 {
1407 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) 1011 maxDepthContact.Position.X = curContact.pos.X;
1408 { 1012 maxDepthContact.Position.Y = curContact.pos.Y;
1409 result = true; 1013 maxDepthContact.Position.Z = curContact.pos.Z;
1410 break; 1014 maxDepthContact.PenetrationDepth = curContact.depth;
1411 } 1015 maxDepthContact.CharacterFeet = FeetCollision;
1412 } 1016 }
1413 } 1017
1414 else if (at == ActorTypes.Prim) 1018 if (curContact.depth < minDepthContact.PenetrationDepth)
1415 {
1416 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1417 { 1019 {
1418 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) 1020 minDepthContact.PenetrationDepth = curContact.depth;
1419 { 1021 minDepthContact.SurfaceNormal.X = curContact.normal.X;
1420 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) 1022 minDepthContact.SurfaceNormal.Y = curContact.normal.Y;
1421 { 1023 minDepthContact.SurfaceNormal.Z = curContact.normal.Z;
1422 result = true;
1423 break;
1424 }
1425 }
1426 //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1427 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1428 } 1024 }
1429 } 1025 }
1026
1027 if (++i >= count)
1028 break;
1029
1030 if (!GetCurContactGeom(i, ref curContact))
1031 break;
1430 } 1032 }
1431 1033
1432 return result; 1034 if (ncontacts > 0)
1035 {
1036 maxDepthContact.SurfaceNormal.X = minDepthContact.SurfaceNormal.X;
1037 maxDepthContact.SurfaceNormal.Y = minDepthContact.SurfaceNormal.Y;
1038 maxDepthContact.SurfaceNormal.Z = minDepthContact.SurfaceNormal.Z;
1039
1040 collision_accounting_events(p1, p2, maxDepthContact);
1041 }
1433 } 1042 }
1434 1043
1435 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) 1044 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1436 { 1045 {
1437 // obj1LocalID = 0; 1046 uint obj2LocalID = 0;
1438 //returncollisions = false; 1047
1439 obj2LocalID = 0; 1048 // update actors collision score
1440 //ctype = 0; 1049 if (p1.CollisionScore < float.MaxValue)
1441 //cStartStop = 0; 1050 p1.CollisionScore += 1.0f;
1442// if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) 1051 if (p2.CollisionScore < float.MaxValue)
1443// return; 1052 p2.CollisionScore += 1.0f;
1053
1444 bool p1events = p1.SubscribedEvents(); 1054 bool p1events = p1.SubscribedEvents();
1445 bool p2events = p2.SubscribedEvents(); 1055 bool p2events = p2.SubscribedEvents();
1446 1056
@@ -1454,799 +1064,379 @@ namespace OpenSim.Region.PhysicsModule.ODE
1454 1064
1455 Vector3 vel = Vector3.Zero; 1065 Vector3 vel = Vector3.Zero;
1456 if (p2 != null && p2.IsPhysical) 1066 if (p2 != null && p2.IsPhysical)
1457 vel = p2.Velocity; 1067 vel = p2.rootVelocity;
1458 1068
1459 if (p1 != null && p1.IsPhysical) 1069 if (p1 != null && p1.IsPhysical)
1460 vel -= p1.Velocity; 1070 vel -= p1.rootVelocity;
1461 1071
1462 contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal); 1072 contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal);
1463 1073
1464 switch ((ActorTypes)p2.PhysicsActorType) 1074 switch ((ActorTypes)p1.PhysicsActorType)
1465 { 1075 {
1466 case ActorTypes.Agent: 1076 case ActorTypes.Agent:
1467 cc2 = (OdeCharacter)p2; 1077 case ActorTypes.Prim:
1468 1078 {
1469 // obj1LocalID = cc2.m_localID; 1079 switch ((ActorTypes)p2.PhysicsActorType)
1470 switch ((ActorTypes)p1.PhysicsActorType)
1471 { 1080 {
1472 case ActorTypes.Agent: 1081 case ActorTypes.Agent:
1473 cc1 = (OdeCharacter)p1;
1474 obj2LocalID = cc1.LocalID;
1475 cc1.AddCollisionEvent(cc2.LocalID, contact);
1476 break;
1477
1478 case ActorTypes.Prim: 1082 case ActorTypes.Prim:
1479 if (p1 is OdePrim) 1083 if (p2events)
1480 { 1084 {
1481 cp1 = (OdePrim) p1; 1085 AddCollisionEventReporting(p2);
1482 obj2LocalID = cp1.LocalID; 1086 p2.AddCollisionEvent(p1.ParentActor.LocalID, contact);
1483 cp1.AddCollisionEvent(cc2.LocalID, contact);
1484 } 1087 }
1088 obj2LocalID = p2.ParentActor.LocalID;
1485 break; 1089 break;
1486 1090
1487 case ActorTypes.Ground: 1091 case ActorTypes.Ground:
1488 case ActorTypes.Unknown: 1092 case ActorTypes.Unknown:
1093 default:
1489 obj2LocalID = 0; 1094 obj2LocalID = 0;
1490 break; 1095 break;
1491 } 1096 }
1492 1097 if (p1events)
1493 cc2.AddCollisionEvent(obj2LocalID, contact); 1098 {
1099 contact.SurfaceNormal = -contact.SurfaceNormal;
1100 contact.RelativeSpeed = -contact.RelativeSpeed;
1101 AddCollisionEventReporting(p1);
1102 p1.AddCollisionEvent(obj2LocalID, contact);
1103 }
1494 break; 1104 break;
1495 1105 }
1496 case ActorTypes.Prim: 1106 case ActorTypes.Ground:
1497 1107 case ActorTypes.Unknown:
1498 if (p2 is OdePrim) 1108 default:
1109 {
1110 if (p2events && !p2.IsVolumeDtc)
1499 { 1111 {
1500 cp2 = (OdePrim) p2; 1112 AddCollisionEventReporting(p2);
1501 1113 p2.AddCollisionEvent(0, contact);
1502 // obj1LocalID = cp2.m_localID;
1503 switch ((ActorTypes) p1.PhysicsActorType)
1504 {
1505 case ActorTypes.Agent:
1506 if (p1 is OdeCharacter)
1507 {
1508 cc1 = (OdeCharacter) p1;
1509 obj2LocalID = cc1.LocalID;
1510 cc1.AddCollisionEvent(cp2.LocalID, contact);
1511 }
1512 break;
1513 case ActorTypes.Prim:
1514
1515 if (p1 is OdePrim)
1516 {
1517 cp1 = (OdePrim) p1;
1518 obj2LocalID = cp1.LocalID;
1519 cp1.AddCollisionEvent(cp2.LocalID, contact);
1520 }
1521 break;
1522
1523 case ActorTypes.Ground:
1524 case ActorTypes.Unknown:
1525 obj2LocalID = 0;
1526 break;
1527 }
1528
1529 cp2.AddCollisionEvent(obj2LocalID, contact);
1530 } 1114 }
1531 break; 1115 break;
1116 }
1532 } 1117 }
1533 } 1118 }
1119
1534 /// <summary> 1120 /// <summary>
1535 /// This is our collision testing routine in ODE 1121 /// This is our collision testing routine in ODE
1536 /// </summary> 1122 /// </summary>
1123 /// <param name="timeStep"></param>
1537 private void collision_optimized() 1124 private void collision_optimized()
1538 { 1125 {
1539 _perloopContact.Clear(); 1126 lock (_characters)
1540 1127 {
1541 foreach (OdeCharacter chr in _characters)
1542 {
1543 // Reset the collision values to false
1544 // since we don't know if we're colliding yet
1545 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1546 continue;
1547
1548 chr.IsColliding = false;
1549 chr.CollidingGround = false;
1550 chr.CollidingObj = false;
1551
1552 // Test the avatar's geometry for collision with the space
1553 // This will return near and the space that they are the closest to
1554 // And we'll run this again against the avatar and the space segment
1555 // This will return with a bunch of possible objects in the space segment
1556 // and we'll run it again on all of them.
1557 try 1128 try
1558 { 1129 {
1559 CollideSpaces(space, chr.Shell, IntPtr.Zero); 1130 foreach (OdeCharacter chr in _characters)
1131 {
1132 if (chr == null)
1133 continue;
1134
1135 chr.IsColliding = false;
1136 // chr.CollidingGround = false; not done here
1137 chr.CollidingObj = false;
1138
1139 if(chr.Body == IntPtr.Zero || chr.collider == IntPtr.Zero )
1140 continue;
1141
1142 // do colisions with static space
1143 d.SpaceCollide2(chr.collider, StaticSpace, IntPtr.Zero, nearCallback);
1144
1145 // no coll with gnd
1146 }
1147 // chars with chars
1148 d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback);
1149
1560 } 1150 }
1561 catch (AccessViolationException) 1151 catch (AccessViolationException)
1562 { 1152 {
1563 m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName); 1153 m_log.Warn("[PHYSICS]: Unable to collide Character to static space");
1564 } 1154 }
1565
1566 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1567 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1568 //{
1569 //chr.Position.Z = terrainheight + 10.0f;
1570 //forcedZ = true;
1571 //}
1572 }
1573 1155
1574 if (CollectStats)
1575 {
1576 m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
1577 m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
1578 } 1156 }
1579 1157
1580 List<OdePrim> removeprims = null; 1158 lock (_activeprims)
1581 foreach (OdePrim chr in _activeprims)
1582 { 1159 {
1583 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) 1160 foreach (OdePrim aprim in _activeprims)
1584 { 1161 {
1585 try 1162 aprim.CollisionScore = 0;
1586 { 1163 aprim.IsColliding = false;
1587 lock (chr)
1588 {
1589 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1590 {
1591 CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
1592 }
1593 else
1594 {
1595 if (removeprims == null)
1596 {
1597 removeprims = new List<OdePrim>();
1598 }
1599 removeprims.Add(chr);
1600 m_log.Error(
1601 "[ODE SCENE]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1602 }
1603 }
1604 }
1605 catch (AccessViolationException)
1606 {
1607 m_log.Error("[ODE SCENE]: Unable to space collide");
1608 }
1609 } 1164 }
1610 } 1165 }
1611 1166 lock (_activegroups)
1612 if (CollectStats)
1613 m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
1614
1615 if (removeprims != null)
1616 {
1617 foreach (OdePrim chr in removeprims)
1618 {
1619 _activeprims.Remove(chr);
1620 }
1621 }
1622 }
1623
1624 #endregion
1625
1626 // Recovered for use by fly height. Kitto Flora
1627 internal float GetTerrainHeightAtXY(float x, float y)
1628 {
1629 IntPtr heightFieldGeom = IntPtr.Zero;
1630 int offsetX = 0;
1631 int offsetY = 0;
1632
1633 if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1634 { 1167 {
1635 if (heightFieldGeom != IntPtr.Zero) 1168 try
1636 { 1169 {
1637 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) 1170 foreach (OdePrim aprim in _activegroups)
1638 { 1171 {
1639 1172 if(!aprim.m_outbounds && d.BodyIsEnabled(aprim.Body) &&
1640 int index; 1173 aprim.collide_geom != IntPtr.Zero)
1641
1642
1643 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1644 (int)x < 0.001f || (int)y < 0.001f)
1645 return 0;
1646
1647 x = x - offsetX + 1f;
1648 y = y - offsetY + 1f;
1649
1650 // map is rotated
1651 index = (int)x * ((int)m_regionHeight + 3) + (int)y;
1652
1653 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1654 { 1174 {
1655 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); 1175 d.SpaceCollide2(StaticSpace, aprim.collide_geom, IntPtr.Zero, nearCallback);
1656 return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; 1176 d.SpaceCollide2(GroundSpace, aprim.collide_geom, IntPtr.Zero, nearCallback);
1657 } 1177 }
1658
1659 else
1660 return 0f;
1661 } 1178 }
1662 else
1663 {
1664 return 0f;
1665 }
1666
1667 } 1179 }
1668 else 1180 catch (Exception e)
1669 { 1181 {
1670 return 0f; 1182 m_log.Warn("[PHYSICS]: Unable to collide Active to Static: " + e.Message);
1671 } 1183 }
1184 }
1672 1185
1186 // colide active amoung them
1187 try
1188 {
1189 d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback);
1673 } 1190 }
1674 else 1191 catch (Exception e)
1675 { 1192 {
1676 return 0f; 1193 m_log.Warn("[PHYSICS]: Unable to collide in Active: " + e.Message);
1677 } 1194 }
1678 }
1679// End recovered. Kitto Flora
1680 1195
1196 // and with chars
1197 try
1198 {
1199 d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback);
1200 }
1201 catch (Exception e)
1202 {
1203 m_log.Warn("[PHYSICS]: Unable to collide Active to Character: " + e.Message);
1204 }
1205 }
1206
1207 #endregion
1681 /// <summary> 1208 /// <summary>
1682 /// Add actor to the list that should receive collision events in the simulate loop. 1209 /// Add actor to the list that should receive collision events in the simulate loop.
1683 /// </summary> 1210 /// </summary>
1684 /// <param name="obj"></param> 1211 /// <param name="obj"></param>
1685 internal void AddCollisionEventReporting(PhysicsActor obj) 1212 public void AddCollisionEventReporting(PhysicsActor obj)
1686 { 1213 {
1687// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); 1214 if (!_collisionEventPrim.Contains(obj))
1688 1215 _collisionEventPrim.Add(obj);
1689 lock (m_collisionEventActorsChanges)
1690 m_collisionEventActorsChanges[obj.LocalID] = obj;
1691 } 1216 }
1692 1217
1693 /// <summary> 1218 /// <summary>
1694 /// Remove actor from the list that should receive collision events in the simulate loop. 1219 /// Remove actor from the list that should receive collision events in the simulate loop.
1695 /// </summary> 1220 /// </summary>
1696 /// <param name="obj"></param> 1221 /// <param name="obj"></param>
1697 internal void RemoveCollisionEventReporting(PhysicsActor obj) 1222 public void RemoveCollisionEventReporting(PhysicsActor obj)
1223 {
1224 lock(_collisionEventPrimRemove)
1225 {
1226 if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj))
1227 _collisionEventPrimRemove.Add(obj);
1228 }
1229 }
1230
1231 public override float TimeDilation
1698 { 1232 {
1699// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); 1233 get { return m_timeDilation; }
1234 }
1700 1235
1701 lock (m_collisionEventActorsChanges) 1236 public override bool SupportsNINJAJoints
1702 m_collisionEventActorsChanges[obj.LocalID] = null; 1237 {
1238 get { return false; }
1703 } 1239 }
1704 1240
1705 #region Add/Remove Entities 1241 #region Add/Remove Entities
1706 1242
1707 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) 1243 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
1708 { 1244 {
1709 d.AllocateODEDataForThread(0); 1245 return null;
1710 1246 }
1711 OdeCharacter newAv
1712 = new OdeCharacter(
1713 avName, this, position, velocity, size, avPIDD, avPIDP,
1714 avCapRadius, avStandupTensor, avDensity,
1715 avMovementDivisorWalk, avMovementDivisorRun);
1716 1247
1248 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, float feetOffset, bool isFlying)
1249 {
1250 OdeCharacter newAv = new OdeCharacter(localID, avName, this, position,
1251 size, feetOffset, avDensity, avMovementDivisorWalk, avMovementDivisorRun);
1717 newAv.Flying = isFlying; 1252 newAv.Flying = isFlying;
1718 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; 1253 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1719 newAv.m_avatarplanted = avplanted; 1254
1720
1721 return newAv; 1255 return newAv;
1722 } 1256 }
1723 1257
1724 public override void RemoveAvatar(PhysicsActor actor) 1258 public void AddCharacter(OdeCharacter chr)
1725 { 1259 {
1726// m_log.DebugFormat( 1260 lock (_characters)
1727// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}",
1728// actor.Name, actor.LocalID, Name);
1729
1730 lock (OdeLock)
1731 { 1261 {
1732 d.AllocateODEDataForThread(0); 1262 if (!_characters.Contains(chr))
1733 1263 {
1734 ((OdeCharacter) actor).Destroy(); 1264 _characters.Add(chr);
1265 if (chr.bad)
1266 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1267 }
1735 } 1268 }
1736 } 1269 }
1737 1270
1738 internal void AddCharacter(OdeCharacter chr) 1271 public void RemoveCharacter(OdeCharacter chr)
1739 { 1272 {
1740 chr.m_avatarplanted = avplanted; 1273 lock (_characters)
1741 if (!_characters.Contains(chr))
1742 {
1743 _characters.Add(chr);
1744
1745// m_log.DebugFormat(
1746// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}",
1747// chr.Name, chr.LocalID, Name, _characters.Count);
1748
1749 if (chr.bad)
1750 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid);
1751 }
1752 else
1753 { 1274 {
1754 m_log.ErrorFormat( 1275 if (_characters.Contains(chr))
1755 "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!", 1276 {
1756 chr.Name, chr.LocalID); 1277 _characters.Remove(chr);
1278 }
1757 } 1279 }
1758 } 1280 }
1759 1281
1760 internal void RemoveCharacter(OdeCharacter chr) 1282 public void BadCharacter(OdeCharacter chr)
1761 { 1283 {
1762 if (_characters.Contains(chr)) 1284 lock (_badCharacter)
1763 { 1285 {
1764 _characters.Remove(chr); 1286 if (!_badCharacter.Contains(chr))
1765 1287 _badCharacter.Add(chr);
1766// m_log.DebugFormat(
1767// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}",
1768// chr.Name, chr.LocalID, Name, _characters.Count);
1769 }
1770 else
1771 {
1772 m_log.ErrorFormat(
1773 "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!",
1774 chr.Name, chr.LocalID);
1775 } 1288 }
1776 } 1289 }
1777 1290
1778 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, 1291 public override void RemoveAvatar(PhysicsActor actor)
1779 PrimitiveBaseShape pbs, bool isphysical, uint localID)
1780 { 1292 {
1781 Vector3 pos = position; 1293 //m_log.Debug("[PHYSICS]:ODELOCK");
1782 Vector3 siz = size;
1783 Quaternion rot = rotation;
1784
1785
1786 OdePrim newPrim;
1787 lock (OdeLock) 1294 lock (OdeLock)
1788 { 1295 {
1789 d.AllocateODEDataForThread(0); 1296 d.AllocateODEDataForThread(0);
1790 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); 1297 ((OdeCharacter) actor).Destroy();
1791
1792 lock (_prims)
1793 _prims.Add(newPrim);
1794 } 1298 }
1795 newPrim.LocalID = localID;
1796 return newPrim;
1797 } 1299 }
1798 1300
1799 /// <summary>
1800 /// Make this prim subject to physics.
1801 /// </summary>
1802 /// <param name="prim"></param>
1803 internal void ActivatePrim(OdePrim prim)
1804 {
1805 // adds active prim.. (ones that should be iterated over in collisions_optimized
1806 if (!_activeprims.Contains(prim))
1807 _activeprims.Add(prim);
1808 //else
1809 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1810 }
1811 1301
1812 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, 1302 public void addActivePrim(OdePrim activatePrim)
1813 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
1814 { 1303 {
1815// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name); 1304 // adds active prim..
1816 1305 lock (_activeprims)
1817 return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); 1306 {
1307 if (!_activeprims.Contains(activatePrim))
1308 _activeprims.Add(activatePrim);
1309 }
1818 } 1310 }
1819 1311
1820 public override float TimeDilation 1312 public void addActiveGroups(OdePrim activatePrim)
1821 { 1313 {
1822 get { return m_timeDilation; } 1314 lock (_activegroups)
1315 {
1316 if (!_activegroups.Contains(activatePrim))
1317 _activegroups.Add(activatePrim);
1318 }
1823 } 1319 }
1824 1320
1825 public override bool SupportsNINJAJoints 1321 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1322 PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID)
1826 { 1323 {
1827 get { return m_NINJA_physics_joints_enabled; } 1324 OdePrim newPrim;
1325 lock (OdeLock)
1326 {
1327
1328 newPrim = new OdePrim(name, this, position, size, rotation, pbs, isphysical, isPhantom, shapeType, localID);
1329 }
1330 return newPrim;
1828 } 1331 }
1829 1332
1830 // internal utility function: must be called within a lock (OdeLock) 1333 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1831 private void InternalAddActiveJoint(PhysicsJoint joint) 1334 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid)
1832 { 1335 {
1833 activeJoints.Add(joint); 1336 return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, 0 , localid);
1834 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1835 } 1337 }
1836 1338
1837 // internal utility function: must be called within a lock (OdeLock)
1838 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1839 {
1840 pendingJoints.Add(joint);
1841 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1842 }
1843 1339
1844 // internal utility function: must be called within a lock (OdeLock) 1340 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1845 private void InternalRemovePendingJoint(PhysicsJoint joint) 1341 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
1846 { 1342 {
1847 pendingJoints.Remove(joint); 1343 return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid);
1848 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1849 } 1344 }
1850 1345
1851 // internal utility function: must be called within a lock (OdeLock) 1346 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1852 private void InternalRemoveActiveJoint(PhysicsJoint joint) 1347 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid)
1853 { 1348 {
1854 activeJoints.Remove(joint); 1349 return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid);
1855 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1856 } 1350 }
1857 1351
1858 public override void DumpJointInfo() 1352 public void remActivePrim(OdePrim deactivatePrim)
1859 { 1353 {
1860 string hdr = "[NINJA] JOINTINFO: "; 1354 lock (_activeprims)
1861 foreach (PhysicsJoint j in pendingJoints)
1862 {
1863 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1864 }
1865 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1866 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1867 {
1868 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1869 }
1870 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1871 foreach (PhysicsJoint j in activeJoints)
1872 {
1873 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1874 }
1875 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1876 foreach (string jointName in SOPName_to_activeJoint.Keys)
1877 { 1355 {
1878 m_log.Debug(hdr + " active joints dict contains Name: " + jointName); 1356 _activeprims.Remove(deactivatePrim);
1879 }
1880 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1881
1882 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1883 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1884 foreach (string actorName in joints_connecting_actor.Keys)
1885 {
1886 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1887 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1888 {
1889 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1890 }
1891 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1892 } 1357 }
1893 } 1358 }
1894 1359 public void remActiveGroup(OdePrim deactivatePrim)
1895 public override void RequestJointDeletion(string ObjectNameInScene)
1896 { 1360 {
1897 lock (externalJointRequestsLock) 1361 lock (_activegroups)
1898 { 1362 {
1899 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously 1363 _activegroups.Remove(deactivatePrim);
1900 {
1901 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1902 }
1903 } 1364 }
1904 } 1365 }
1905 1366
1906 private void DeleteRequestedJoints() 1367 public override void RemovePrim(PhysicsActor prim)
1907 {
1908 List<string> myRequestedJointsToBeDeleted;
1909 lock (externalJointRequestsLock)
1910 {
1911 // make a local copy of the shared list for processing (threading issues)
1912 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1913 }
1914
1915 foreach (string jointName in myRequestedJointsToBeDeleted)
1916 {
1917 lock (OdeLock)
1918 {
1919 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1920 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1921 {
1922 OdePhysicsJoint joint = null;
1923 if (SOPName_to_activeJoint.ContainsKey(jointName))
1924 {
1925 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1926 InternalRemoveActiveJoint(joint);
1927 }
1928 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1929 {
1930 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1931 InternalRemovePendingJoint(joint);
1932 }
1933
1934 if (joint != null)
1935 {
1936 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1937 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1938 {
1939 string bodyName = joint.BodyNames[iBodyName];
1940 if (bodyName != "NULL")
1941 {
1942 joints_connecting_actor[bodyName].Remove(joint);
1943 if (joints_connecting_actor[bodyName].Count == 0)
1944 {
1945 joints_connecting_actor.Remove(bodyName);
1946 }
1947 }
1948 }
1949
1950 DoJointDeactivated(joint);
1951 if (joint.jointID != IntPtr.Zero)
1952 {
1953 d.JointDestroy(joint.jointID);
1954 joint.jointID = IntPtr.Zero;
1955 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1956 }
1957 else
1958 {
1959 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1960 }
1961 }
1962 else
1963 {
1964 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1965 }
1966 }
1967 else
1968 {
1969 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1970 }
1971 }
1972 }
1973
1974 // remove processed joints from the shared list
1975 lock (externalJointRequestsLock)
1976 {
1977 foreach (string jointName in myRequestedJointsToBeDeleted)
1978 {
1979 requestedJointsToBeDeleted.Remove(jointName);
1980 }
1981 }
1982 }
1983
1984 // for pending joints we don't know if their associated bodies exist yet or not.
1985 // the joint is actually created during processing of the taints
1986 private void CreateRequestedJoints()
1987 { 1368 {
1988 List<PhysicsJoint> myRequestedJointsToBeCreated; 1369 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
1989 lock (externalJointRequestsLock) 1370 // removed in the next physics simulate pass.
1990 { 1371 if (prim is OdePrim)
1991 // make a local copy of the shared list for processing (threading issues)
1992 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1993 }
1994
1995 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1996 {
1997 lock (OdeLock)
1998 {
1999 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
2000 {
2001 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
2002 continue;
2003 }
2004 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
2005 {
2006 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
2007 continue;
2008 }
2009
2010 InternalAddPendingJoint(joint as OdePhysicsJoint);
2011
2012 if (joint.BodyNames.Count >= 2)
2013 {
2014 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2015 {
2016 string bodyName = joint.BodyNames[iBodyName];
2017 if (bodyName != "NULL")
2018 {
2019 if (!joints_connecting_actor.ContainsKey(bodyName))
2020 {
2021 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
2022 }
2023 joints_connecting_actor[bodyName].Add(joint);
2024 }
2025 }
2026 }
2027 }
2028 }
2029
2030 // remove processed joints from shared list
2031 lock (externalJointRequestsLock)
2032 { 1372 {
2033 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) 1373// lock (OdeLock)
2034 { 1374 {
2035 requestedJointsToBeCreated.Remove(joint); 1375
1376 OdePrim p = (OdePrim)prim;
1377 p.setPrimForRemoval();
2036 } 1378 }
2037 } 1379 }
2038 } 1380 }
2039 1381
2040 /// <summary> 1382 public void RemovePrimThreadLocked(OdePrim prim)
2041 /// Add a request for joint creation.
2042 /// </summary>
2043 /// <remarks>
2044 /// this joint will just be added to a waiting list that is NOT processed during the main
2045 /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2046 /// </remarks>
2047 /// <param name="objectNameInScene"></param>
2048 /// <param name="jointType"></param>
2049 /// <param name="position"></param>
2050 /// <param name="rotation"></param>
2051 /// <param name="parms"></param>
2052 /// <param name="bodyNames"></param>
2053 /// <param name="trackedBodyName"></param>
2054 /// <param name="localRotation"></param>
2055 /// <returns></returns>
2056 public override PhysicsJoint RequestJointCreation(
2057 string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2058 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2059 { 1383 {
2060 OdePhysicsJoint joint = new OdePhysicsJoint(); 1384 //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2061 joint.ObjectNameInScene = objectNameInScene; 1385 lock (prim)
2062 joint.Type = jointType;
2063 joint.Position = position;
2064 joint.Rotation = rotation;
2065 joint.RawParams = parms;
2066 joint.BodyNames = new List<string>(bodyNames);
2067 joint.TrackedBodyName = trackedBodyName;
2068 joint.LocalRotation = localRotation;
2069 joint.jointID = IntPtr.Zero;
2070 joint.ErrorMessageCount = 0;
2071
2072 lock (externalJointRequestsLock)
2073 { 1386 {
2074 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice 1387// RemoveCollisionEventReporting(prim);
2075 { 1388 lock (_prims)
2076 requestedJointsToBeCreated.Add(joint); 1389 _prims.Remove(prim.LocalID);
2077 }
2078 } 1390 }
2079 1391
2080 return joint;
2081 } 1392 }
2082 1393
2083 private void RemoveAllJointsConnectedToActor(PhysicsActor actor) 1394 public void addToPrims(OdePrim prim)
2084 { 1395 {
2085 //m_log.Debug("RemoveAllJointsConnectedToActor: start"); 1396 lock (_prims)
2086 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null) 1397 _prims[prim.LocalID] = prim;
2087 {
2088 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2089 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2090 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2091 {
2092 jointsToRemove.Add(j);
2093 }
2094 foreach (PhysicsJoint j in jointsToRemove)
2095 {
2096 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2097 RequestJointDeletion(j.ObjectNameInScene);
2098 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2099 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2100 }
2101 }
2102 } 1398 }
2103 1399
2104 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) 1400 public OdePrim getPrim(uint id)
2105 { 1401 {
2106 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); 1402 lock (_prims)
2107 lock (OdeLock)
2108 { 1403 {
2109 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); 1404 if(_prims.ContainsKey(id))
2110 RemoveAllJointsConnectedToActor(actor); 1405 return _prims[id];
1406 else
1407 return null;
2111 } 1408 }
2112 } 1409 }
2113 1410
2114 // normally called from within OnJointMoved, which is called from within a lock (OdeLock) 1411 public bool havePrim(OdePrim prm)
2115 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2116 { 1412 {
2117 Debug.Assert(joint.IsInPhysicsEngine); 1413 lock (_prims)
2118 d.Vector3 pos = new d.Vector3(); 1414 return _prims.ContainsKey(prm.LocalID);
2119
2120 if (!(joint is OdePhysicsJoint))
2121 {
2122 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2123 }
2124 else
2125 {
2126 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2127 switch (odeJoint.Type)
2128 {
2129 case PhysicsJointType.Ball:
2130 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2131 break;
2132 case PhysicsJointType.Hinge:
2133 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2134 break;
2135 }
2136 }
2137 return new Vector3(pos.X, pos.Y, pos.Z);
2138 } 1415 }
2139 1416
2140 /// <summary> 1417 public void changePrimID(OdePrim prim,uint oldID)
2141 /// Get joint axis.
2142 /// </summary>
2143 /// <remarks>
2144 /// normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2145 /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2146 /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2147 /// keeping track of the joint's original orientation relative to one of the involved bodies.
2148 /// </remarks>
2149 /// <param name="joint"></param>
2150 /// <returns></returns>
2151 public override Vector3 GetJointAxis(PhysicsJoint joint)
2152 { 1418 {
2153 Debug.Assert(joint.IsInPhysicsEngine); 1419 lock (_prims)
2154 d.Vector3 axis = new d.Vector3();
2155
2156 if (!(joint is OdePhysicsJoint))
2157 {
2158 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2159 }
2160 else
2161 { 1420 {
2162 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; 1421 if(_prims.ContainsKey(oldID))
2163 switch (odeJoint.Type) 1422 _prims.Remove(oldID);
2164 { 1423 _prims[prim.LocalID] = prim;
2165 case PhysicsJointType.Ball:
2166 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2167 break;
2168 case PhysicsJointType.Hinge:
2169 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2170 break;
2171 }
2172 } 1424 }
2173 return new Vector3(axis.X, axis.Y, axis.Z);
2174 } 1425 }
2175 1426
2176 /// <summary> 1427 public bool haveActor(PhysicsActor actor)
2177 /// Stop this prim being subject to physics
2178 /// </summary>
2179 /// <param name="prim"></param>
2180 internal void DeactivatePrim(OdePrim prim)
2181 {
2182 _activeprims.Remove(prim);
2183 }
2184
2185 public override void RemovePrim(PhysicsActor prim)
2186 { 1428 {
2187 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be 1429 if (actor is OdePrim)
2188 // removed in the next physics simulate pass.
2189 if (prim is OdePrim)
2190 { 1430 {
2191 lock (OdeLock) 1431 lock (_prims)
2192 { 1432 return _prims.ContainsKey(((OdePrim)actor).LocalID);
2193 OdePrim p = (OdePrim) prim;
2194
2195 p.setPrimForRemoval();
2196 AddPhysicsActorTaint(prim);
2197 }
2198 } 1433 }
2199 } 1434 else if (actor is OdeCharacter)
2200
2201 /// <summary>
2202 /// This is called from within simulate but outside the locked portion
2203 /// We need to do our own locking here
2204 /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in
2205 /// Simulate() -- justincc).
2206 ///
2207 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2208 ///
2209 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2210 /// that the space was using.
2211 /// </summary>
2212 /// <param name="prim"></param>
2213 internal void RemovePrimThreadLocked(OdePrim prim)
2214 {
2215// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID);
2216
2217 lock (prim)
2218 { 1435 {
2219 RemoveCollisionEventReporting(prim); 1436 lock (_characters)
2220 1437 return _characters.Contains((OdeCharacter)actor);
2221 if (prim.prim_geom != IntPtr.Zero)
2222 {
2223 prim.ResetTaints();
2224
2225 if (prim.IsPhysical)
2226 {
2227 prim.disableBody();
2228 if (prim.childPrim)
2229 {
2230 prim.childPrim = false;
2231 prim.Body = IntPtr.Zero;
2232 prim.m_disabled = true;
2233 prim.IsPhysical = false;
2234 }
2235
2236
2237 }
2238 prim.m_targetSpace = IntPtr.Zero;
2239 if (!prim.RemoveGeom())
2240 m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene");
2241
2242 lock (_prims)
2243 _prims.Remove(prim);
2244
2245
2246 if (SupportsNINJAJoints)
2247 RemoveAllJointsConnectedToActorThreadLocked(prim);
2248 }
2249 } 1438 }
1439 return false;
2250 } 1440 }
2251 1441
2252 #endregion 1442 #endregion
@@ -2254,368 +1444,126 @@ namespace OpenSim.Region.PhysicsModule.ODE
2254 #region Space Separation Calculation 1444 #region Space Separation Calculation
2255 1445
2256 /// <summary> 1446 /// <summary>
2257 /// Takes a space pointer and zeros out the array we're using to hold the spaces 1447 /// Called when a static prim moves or becomes static
2258 /// </summary> 1448 /// Places the prim in a space one the static sub-spaces grid
2259 /// <param name="pSpace"></param>
2260 private void resetSpaceArrayItemToZero(IntPtr pSpace)
2261 {
2262 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2263 {
2264 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2265 {
2266 if (staticPrimspace[x, y] == pSpace)
2267 staticPrimspace[x, y] = IntPtr.Zero;
2268 }
2269 }
2270 }
2271
2272// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2273// {
2274// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2275// }
2276
2277 /// <summary>
2278 /// Called when a static prim moves. Allocates a space for the prim based on its position
2279 /// </summary> 1449 /// </summary>
2280 /// <param name="geom">the pointer to the geom that moved</param> 1450 /// <param name="geom">the pointer to the geom that moved</param>
2281 /// <param name="pos">the position that the geom moved to</param> 1451 /// <param name="pos">the position that the geom moved to</param>
2282 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param> 1452 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2283 /// <returns>a pointer to the new space it's in</returns> 1453 /// <returns>a pointer to the new space it's in</returns>
2284 internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) 1454 public IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace)
2285 { 1455 {
2286 // Called from setting the Position and Size of an ODEPrim so 1456 // moves a prim into another static sub-space or from another space into a static sub-space
1457
1458 // Called ODEPrim so
2287 // it's already in locked space. 1459 // it's already in locked space.
2288 1460
2289 // we don't want to remove the main space 1461 if (geom == IntPtr.Zero) // shouldn't happen
2290 // we don't need to test physical here because this function should 1462 return IntPtr.Zero;
2291 // never be called if the prim is physical(active) 1463
1464 // get the static sub-space for current position
1465 IntPtr newspace = calculateSpaceForGeom(pos);
1466
1467 if (newspace == currentspace) // if we are there all done
1468 return newspace;
2292 1469
2293 // All physical prim end up in the root space 1470 // else remove it from its current space
2294 //Thread.Sleep(20); 1471 if (currentspace != IntPtr.Zero && d.SpaceQuery(currentspace, geom))
2295 if (currentspace != space)
2296 { 1472 {
2297 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); 1473 if (d.GeomIsSpace(currentspace))
2298 //if (currentspace == IntPtr.Zero)
2299 //{
2300 //int adfadf = 0;
2301 //}
2302 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2303 { 1474 {
2304 if (d.GeomIsSpace(currentspace)) 1475 waitForSpaceUnlock(currentspace);
2305 { 1476 d.SpaceRemove(currentspace, geom);
2306// waitForSpaceUnlock(currentspace); 1477
2307 d.SpaceRemove(currentspace, geom); 1478 if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
2308 }
2309 else
2310 { 1479 {
2311 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + 1480 d.SpaceDestroy(currentspace);
2312 " Geom:" + geom);
2313 } 1481 }
2314 } 1482 }
2315 else 1483 else
2316 { 1484 {
2317 IntPtr sGeomIsIn = d.GeomGetSpace(geom); 1485 m_log.Info("[Physics]: Invalid or empty Space passed to 'MoveGeomToStaticSpace':" + currentspace +
2318 if (sGeomIsIn != IntPtr.Zero) 1486 " Geom:" + geom);
2319 {
2320 if (d.GeomIsSpace(currentspace))
2321 {
2322// waitForSpaceUnlock(sGeomIsIn);
2323 d.SpaceRemove(sGeomIsIn, geom);
2324 }
2325 else
2326 {
2327 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2328 sGeomIsIn + " Geom:" + geom);
2329 }
2330 }
2331 }
2332
2333 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2334 if (d.SpaceGetNumGeoms(currentspace) == 0)
2335 {
2336 if (currentspace != IntPtr.Zero)
2337 {
2338 if (d.GeomIsSpace(currentspace))
2339 {
2340 d.SpaceRemove(space, currentspace);
2341 // free up memory used by the space.
2342
2343 resetSpaceArrayItemToZero(currentspace);
2344 }
2345 else
2346 {
2347 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2348 currentspace + " Geom:" + geom);
2349 }
2350 }
2351 } 1487 }
2352 } 1488 }
2353 else 1489 else // odd currentspace is null or doesn't contain the geom? lets try the geom ideia of current space
2354 { 1490 {
2355 // this is a physical object that got disabled. ;.; 1491 currentspace = d.GeomGetSpace(geom);
2356 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) 1492 if (currentspace != IntPtr.Zero)
2357 { 1493 {
2358 if (d.SpaceQuery(currentspace, geom)) 1494 if (d.GeomIsSpace(currentspace))
2359 {
2360 if (d.GeomIsSpace(currentspace))
2361 {
2362// waitForSpaceUnlock(currentspace);
2363 d.SpaceRemove(currentspace, geom);
2364 }
2365 else
2366 {
2367 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2368 currentspace + " Geom:" + geom);
2369 }
2370 }
2371 else
2372 { 1495 {
2373 IntPtr sGeomIsIn = d.GeomGetSpace(geom); 1496 waitForSpaceUnlock(currentspace);
2374 if (sGeomIsIn != IntPtr.Zero) 1497 d.SpaceRemove(currentspace, geom);
1498
1499 if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
2375 { 1500 {
2376 if (d.GeomIsSpace(sGeomIsIn)) 1501 d.SpaceDestroy(currentspace);
2377 {
2378// waitForSpaceUnlock(sGeomIsIn);
2379 d.SpaceRemove(sGeomIsIn, geom);
2380 }
2381 else
2382 {
2383 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2384 sGeomIsIn + " Geom:" + geom);
2385 }
2386 } 1502 }
1503
2387 } 1504 }
2388 } 1505 }
2389 } 1506 }
2390 1507
2391 // The routines in the Position and Size sections do the 'inserting' into the space, 1508 // put the geom in the newspace
2392 // so all we have to do is make sure that the space that we're putting the prim into 1509 waitForSpaceUnlock(newspace);
2393 // is in the 'main' space. 1510 d.SpaceAdd(newspace, geom);
2394 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2395 IntPtr newspace = calculateSpaceForGeom(pos);
2396
2397 if (newspace == IntPtr.Zero)
2398 {
2399 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2400 d.HashSpaceSetLevels(newspace, HashspaceLow, HashspaceHigh);
2401 }
2402 1511
1512 // let caller know this newspace
2403 return newspace; 1513 return newspace;
2404 } 1514 }
2405 1515
2406 /// <summary> 1516 /// <summary>
2407 /// Creates a new space at X Y
2408 /// </summary>
2409 /// <param name="iprimspaceArrItemX"></param>
2410 /// <param name="iprimspaceArrItemY"></param>
2411 /// <returns>A pointer to the created space</returns>
2412 internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2413 {
2414 // creating a new space for prim and inserting it into main space.
2415 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2416 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2417// waitForSpaceUnlock(space);
2418 d.SpaceSetSublevel(space, 1);
2419 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2420
2421 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2422 }
2423
2424 /// <summary>
2425 /// Calculates the space the prim should be in by its position 1517 /// Calculates the space the prim should be in by its position
2426 /// </summary> 1518 /// </summary>
2427 /// <param name="pos"></param> 1519 /// <param name="pos"></param>
2428 /// <returns>a pointer to the space. This could be a new space or reused space.</returns> 1520 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2429 internal IntPtr calculateSpaceForGeom(Vector3 pos) 1521 public IntPtr calculateSpaceForGeom(Vector3 pos)
2430 { 1522 {
2431 int[] xyspace = calculateSpaceArrayItemFromPos(pos); 1523 int x, y;
2432 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2433 return staticPrimspace[xyspace[0], xyspace[1]];
2434 }
2435 1524
2436 /// <summary> 1525 if (pos.X < 0)
2437 /// Holds the space allocation logic 1526 return staticPrimspaceOffRegion[0];
2438 /// </summary>
2439 /// <param name="pos"></param>
2440 /// <returns>an array item based on the position</returns>
2441 internal int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2442 {
2443 int[] returnint = new int[2];
2444
2445 returnint[0] = (int) (pos.X * spacesPerMeterX);
2446 1527
2447 if (returnint[0] > spaceGridMaxX) 1528 if (pos.Y < 0)
2448 returnint[0] = spaceGridMaxX; 1529 return staticPrimspaceOffRegion[2];
2449 if (returnint[0] < 0)
2450 returnint[0] = 0;
2451 1530
2452 returnint[1] = (int)(pos.Y * spacesPerMeterY); 1531 x = (int)(pos.X * spacesPerMeterX);
2453 if (returnint[1] > spaceGridMaxY) 1532 if (x > spaceGridMaxX)
2454 returnint[1] = spaceGridMaxY; 1533 return staticPrimspaceOffRegion[1];
2455 if (returnint[1] < 0) 1534
2456 returnint[1] = 0; 1535 y = (int)(pos.Y * spacesPerMeterY);
1536 if (y > spaceGridMaxY)
1537 return staticPrimspaceOffRegion[3];
2457 1538
2458 return returnint; 1539 return staticPrimspace[x, y];
2459 } 1540 }
2460 1541
2461 #endregion 1542 #endregion
2462 1543
1544
2463 /// <summary> 1545 /// <summary>
2464 /// Routine to figure out if we need to mesh this prim with our mesher 1546 /// Called to queue a change to a actor
1547 /// to use in place of old taint mechanism so changes do have a time sequence
2465 /// </summary> 1548 /// </summary>
2466 /// <param name="pbs"></param>
2467 /// <returns></returns>
2468 internal bool needsMeshing(PrimitiveBaseShape pbs)
2469 {
2470 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2471 // but we still need to check for sculptie meshing being enabled so this is the most
2472 // convenient place to do it for now...
2473
2474 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2475 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2476 int iPropertiesNotSupportedDefault = 0;
2477
2478 if (pbs.SculptEntry && !meshSculptedPrim)
2479 {
2480#if SPAM
2481 m_log.Warn("NonMesh");
2482#endif
2483 return false;
2484 }
2485
2486 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2487 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2488 {
2489 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2490 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2491 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2492 {
2493
2494 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2495 && pbs.ProfileHollow == 0
2496 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2497 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2498 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2499 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2500 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2501 {
2502#if SPAM
2503 m_log.Warn("NonMesh");
2504#endif
2505 return false;
2506 }
2507 }
2508 }
2509
2510 if (pbs.ProfileHollow != 0)
2511 iPropertiesNotSupportedDefault++;
2512
2513 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2514 iPropertiesNotSupportedDefault++;
2515
2516 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2517 iPropertiesNotSupportedDefault++;
2518
2519 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2520 iPropertiesNotSupportedDefault++;
2521
2522 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2523 iPropertiesNotSupportedDefault++;
2524
2525 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2526 iPropertiesNotSupportedDefault++;
2527
2528 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2529 iPropertiesNotSupportedDefault++;
2530
2531 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))
2532 iPropertiesNotSupportedDefault++;
2533
2534 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2535 iPropertiesNotSupportedDefault++;
2536
2537 // test for torus
2538 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2539 {
2540 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2541 {
2542 iPropertiesNotSupportedDefault++;
2543 }
2544 }
2545 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2546 {
2547 if (pbs.PathCurve == (byte)Extrusion.Straight)
2548 {
2549 iPropertiesNotSupportedDefault++;
2550 }
2551
2552 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2553 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2554 {
2555 iPropertiesNotSupportedDefault++;
2556 }
2557 }
2558 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2559 {
2560 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2561 {
2562 iPropertiesNotSupportedDefault++;
2563 }
2564 }
2565 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2566 {
2567 if (pbs.PathCurve == (byte)Extrusion.Straight)
2568 {
2569 iPropertiesNotSupportedDefault++;
2570 }
2571 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2572 {
2573 iPropertiesNotSupportedDefault++;
2574 }
2575 }
2576 1549
2577 if (pbs.SculptEntry && meshSculptedPrim) 1550 public void AddChange(PhysicsActor actor, changes what, Object arg)
2578 iPropertiesNotSupportedDefault++; 1551 {
2579 1552 ODEchangeitem item = new ODEchangeitem();
2580 if (iPropertiesNotSupportedDefault == 0) 1553 item.actor = actor;
2581 { 1554 item.what = what;
2582#if SPAM 1555 item.arg = arg;
2583 m_log.Warn("NonMesh"); 1556 ChangesQueue.Enqueue(item);
2584#endif
2585 return false;
2586 }
2587#if SPAM
2588 m_log.Debug("Mesh");
2589#endif
2590 return true;
2591 } 1557 }
2592 1558
2593 /// <summary> 1559 /// <summary>
2594 /// Called after our prim properties are set Scale, position etc. 1560 /// Called after our prim properties are set Scale, position etc.
2595 /// </summary>
2596 /// <remarks>
2597 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex 1561 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2598 /// This assures us that we have no race conditions 1562 /// This assures us that we have no race conditions
2599 /// </remarks> 1563 /// </summary>
2600 /// <param name="actor"></param> 1564 /// <param name="prim"></param>
2601 public override void AddPhysicsActorTaint(PhysicsActor actor) 1565 public override void AddPhysicsActorTaint(PhysicsActor prim)
2602 { 1566 {
2603 if (actor is OdePrim)
2604 {
2605 OdePrim taintedprim = ((OdePrim)actor);
2606 lock (_taintedPrims)
2607 _taintedPrims.Add(taintedprim);
2608 }
2609 else if (actor is OdeCharacter)
2610 {
2611 OdeCharacter taintedchar = ((OdeCharacter)actor);
2612 lock (_taintedActors)
2613 {
2614 _taintedActors.Add(taintedchar);
2615 if (taintedchar.bad)
2616 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2617 }
2618 }
2619 } 1567 }
2620 1568
2621 // does all pending changes generated during region load process 1569 // does all pending changes generated during region load process
@@ -2625,319 +1573,315 @@ namespace OpenSim.Region.PhysicsModule.ODE
2625 { 1573 {
2626 if (world == IntPtr.Zero) 1574 if (world == IntPtr.Zero)
2627 { 1575 {
2628 _taintedPrims.Clear();; 1576 ChangesQueue.Clear();
2629 return; 1577 return;
2630 } 1578 }
2631 1579
1580 d.AllocateODEDataForThread(~0U);
1581
1582 ODEchangeitem item;
1583
2632 int donechanges = 0; 1584 int donechanges = 0;
2633 if (_taintedPrims.Count > 0) 1585 if (ChangesQueue.Count > 0)
2634 { 1586 {
2635 1587 m_log.InfoFormat("[ubOde] start processing pending actor operations");
2636 m_log.InfoFormat("[Ode] start processing pending actor operations");
2637 int tstart = Util.EnvironmentTickCount(); 1588 int tstart = Util.EnvironmentTickCount();
2638 1589
2639 d.AllocateODEDataForThread(0); 1590 while (ChangesQueue.Dequeue(out item))
2640
2641 lock (_taintedPrims)
2642 { 1591 {
2643 foreach (OdePrim prim in _taintedPrims) 1592 if (item.actor != null)
2644 { 1593 {
2645 if (prim.m_taintremove) 1594 try
2646 RemovePrimThreadLocked(prim); 1595 {
2647 else 1596 if (item.actor is OdeCharacter)
2648 prim.ProcessTaints(); 1597 ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
2649 1598 else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
2650 prim.m_collisionscore = 0; 1599 RemovePrimThreadLocked((OdePrim)item.actor);
2651 donechanges++; 1600 }
1601 catch
1602 {
1603 m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}",
1604 item.actor.Name, item.what.ToString());
1605 }
2652 } 1606 }
2653 _taintedPrims.Clear(); 1607 donechanges++;
2654 } 1608 }
2655
2656 int time = Util.EnvironmentTickCountSubtract(tstart); 1609 int time = Util.EnvironmentTickCountSubtract(tstart);
2657 m_log.InfoFormat("[Ode] finished {0} operations in {1}ms", donechanges, time); 1610 m_log.InfoFormat("[ubOde] finished {0} operations in {1}ms", donechanges, time);
2658 } 1611 }
2659 m_log.InfoFormat("[Ode] {0} prim actors loaded",_prims.Count); 1612 m_log.InfoFormat("[ubOde] {0} prim actors loaded",_prims.Count);
2660 } 1613 }
2661 } 1614 }
2662 1615
2663
2664 /// <summary> 1616 /// <summary>
2665 /// This is our main simulate loop 1617 /// This is our main simulate loop
2666 /// </summary>
2667 /// <remarks>
2668 /// It's thread locked by a Mutex in the scene. 1618 /// It's thread locked by a Mutex in the scene.
2669 /// It holds Collisions, it instructs ODE to step through the physical reactions 1619 /// It holds Collisions, it instructs ODE to step through the physical reactions
2670 /// It moves the objects around in memory 1620 /// It moves the objects around in memory
2671 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) 1621 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2672 /// </remarks> 1622 /// </summary>
2673 /// <param name="timeStep"></param> 1623 /// <param name="timeStep"></param>
2674 /// <returns>The number of frames simulated over that period.</returns> 1624 /// <returns></returns>
2675 public override float Simulate(float timeStep) 1625 public override float Simulate(float reqTimeStep)
2676 { 1626 {
2677 if (!_worldInitialized) 1627 DateTime now = DateTime.UtcNow;
2678 return 1.0f; 1628 TimeSpan timedif = now - m_lastframe;
1629 float timeStep = (float)timedif.TotalSeconds;
1630 m_lastframe = now;
1631
1632 // acumulate time so we can reduce error
1633 step_time += timeStep;
2679 1634
2680 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; 1635 if (step_time < HalfOdeStep)
2681 int tempTick = 0, tempTick2 = 0; 1636 return 0;
2682 1637
2683 if (framecount >= int.MaxValue) 1638 if (framecount < 0)
2684 framecount = 0; 1639 framecount = 0;
2685 1640
2686 framecount++; 1641 framecount++;
2687 1642
1643// checkThread();
1644 int nodeframes = 0;
2688 float fps = 0; 1645 float fps = 0;
2689 1646
2690 step_time += timeStep; 1647 lock (SimulationLock)
2691 1648 lock(OdeLock)
2692 float HalfOdeStep = ODE_STEPSIZE * 0.5f;
2693 if (step_time < HalfOdeStep)
2694 return 0;
2695
2696
2697 // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential
2698 // deadlock if the collision event tries to lock something else later on which is already locked by a
2699 // caller that is adding or removing the collision event.
2700 lock (m_collisionEventActorsChanges)
2701 { 1649 {
2702 foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges) 1650 if (world == IntPtr.Zero)
2703 { 1651 {
2704 if (kvp.Value == null) 1652 ChangesQueue.Clear();
2705 m_collisionEventActors.Remove(kvp.Key); 1653 return 0;
2706 else
2707 m_collisionEventActors[kvp.Key] = kvp.Value;
2708 } 1654 }
2709 1655
2710 m_collisionEventActorsChanges.Clear(); 1656 ODEchangeitem item;
2711 } 1657
2712 1658// d.WorldSetQuickStepNumIterations(world, curphysiteractions);
2713 if (SupportsNINJAJoints) 1659
2714 { 1660 int loopstartMS = Util.EnvironmentTickCount();
2715 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks 1661 int looptimeMS = 0;
2716 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks 1662 int changestimeMS = 0;
2717 } 1663 int maxChangestime = (int)(reqTimeStep * 500f); // half the time
2718 1664 int maxLoopTime = (int)(reqTimeStep * 1200f); // 1.2 the time
2719 1665
2720 lock (OdeLock)
2721 {
2722 d.AllocateODEDataForThread(~0U); 1666 d.AllocateODEDataForThread(~0U);
2723 1667
2724 while (step_time > HalfOdeStep) 1668 if (ChangesQueue.Count > 0)
2725 { 1669 {
2726 try 1670 while (ChangesQueue.Dequeue(out item))
2727 { 1671 {
2728 if (CollectStats) 1672 if (item.actor != null)
2729 tempTick = Util.EnvironmentTickCount();
2730
2731 lock (_taintedActors)
2732 {
2733 foreach (OdeCharacter character in _taintedActors)
2734 character.ProcessTaints();
2735
2736 _taintedActors.Clear();
2737 }
2738
2739 if (CollectStats)
2740 { 1673 {
2741 tempTick2 = Util.EnvironmentTickCount(); 1674 try
2742 m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2743 tempTick = tempTick2;
2744 }
2745
2746 lock (_taintedPrims)
2747 {
2748 foreach (OdePrim prim in _taintedPrims)
2749 { 1675 {
2750 if (prim.m_taintremove) 1676 if (item.actor is OdeCharacter)
2751 { 1677 ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
2752// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); 1678 else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
2753 RemovePrimThreadLocked(prim); 1679 RemovePrimThreadLocked((OdePrim)item.actor);
2754 } 1680 }
2755 else 1681 catch
2756 { 1682 {
2757// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); 1683 m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}",
2758 prim.ProcessTaints(); 1684 item.actor.Name, item.what.ToString());
2759 }
2760
2761 prim.m_collisionscore = 0;
2762
2763 // This loop can block up the Heartbeat for a very long time on large regions.
2764 // We need to let the Watchdog know that the Heartbeat is not dead
2765 // NOTE: This is currently commented out, but if things like OAR loading are
2766 // timing the heartbeat out we will need to uncomment it
2767 //Watchdog.UpdateThread();
2768 } 1685 }
2769
2770 if (SupportsNINJAJoints)
2771 SimulatePendingNINJAJoints();
2772
2773 _taintedPrims.Clear();
2774 } 1686 }
1687 changestimeMS = Util.EnvironmentTickCountSubtract(loopstartMS);
1688 if (changestimeMS > maxChangestime)
1689 break;
1690 }
1691 }
2775 1692
2776 if (CollectStats) 1693 // do simulation taking at most 150ms total time including changes
2777 { 1694 while (step_time > HalfOdeStep)
2778 tempTick2 = Util.EnvironmentTickCount(); 1695 {
2779 m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1696 try
2780 tempTick = tempTick2; 1697 {
2781 } 1698 // clear pointer/counter to contacts to pass into joints
1699 m_global_contactcount = 0;
2782 1700
2783 // Move characters
2784 foreach (OdeCharacter actor in _characters)
2785 actor.Move(defects);
2786 1701
2787 if (defects.Count != 0) 1702 // Move characters
1703 lock (_characters)
2788 { 1704 {
2789 foreach (OdeCharacter actor in defects) 1705 List<OdeCharacter> defects = new List<OdeCharacter>();
1706 foreach (OdeCharacter actor in _characters)
2790 { 1707 {
2791 m_log.ErrorFormat( 1708 if (actor != null)
2792 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", 1709 actor.Move(defects);
2793 actor.Name, actor.LocalID, PhysicsSceneName); 1710 }
2794 1711 if (defects.Count != 0)
2795 RemoveCharacter(actor); 1712 {
2796 actor.DestroyOdeStructures(); 1713 foreach (OdeCharacter defect in defects)
1714 {
1715 RemoveCharacter(defect);
1716 }
1717 defects.Clear();
2797 } 1718 }
2798
2799 defects.Clear();
2800 }
2801
2802 if (CollectStats)
2803 {
2804 tempTick2 = Util.EnvironmentTickCount();
2805 m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2806 tempTick = tempTick2;
2807 } 1719 }
2808 1720
2809 // Move other active objects 1721 // Move other active objects
2810 foreach (OdePrim prim in _activeprims) 1722 lock (_activegroups)
2811 { 1723 {
2812 prim.m_collisionscore = 0; 1724 foreach (OdePrim aprim in _activegroups)
2813 prim.Move(timeStep); 1725 {
2814 } 1726 aprim.Move();
2815 1727 }
2816 if (CollectStats)
2817 {
2818 tempTick2 = Util.EnvironmentTickCount();
2819 m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2820 tempTick = tempTick2;
2821 } 1728 }
2822 1729
2823 m_rayCastManager.ProcessQueuedRequests(); 1730 m_rayCastManager.ProcessQueuedRequests();
2824 1731
2825 if (CollectStats)
2826 {
2827 tempTick2 = Util.EnvironmentTickCount();
2828 m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2829 tempTick = tempTick2;
2830 }
2831
2832 collision_optimized(); 1732 collision_optimized();
1733 List<OdePrim> sleepers = new List<OdePrim>();
2833 1734
2834 if (CollectStats) 1735 foreach (PhysicsActor obj in _collisionEventPrim)
2835 { 1736 {
2836 tempTick2 = Util.EnvironmentTickCount(); 1737 if (obj == null)
2837 m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1738 continue;
2838 tempTick = tempTick2;
2839 }
2840
2841 foreach (PhysicsActor obj in m_collisionEventActors.Values)
2842 {
2843 // m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID);
2844 1739
2845 switch ((ActorTypes)obj.PhysicsActorType) 1740 switch ((ActorTypes)obj.PhysicsActorType)
2846 { 1741 {
2847 case ActorTypes.Agent: 1742 case ActorTypes.Agent:
2848 OdeCharacter cobj = (OdeCharacter)obj; 1743 OdeCharacter cobj = (OdeCharacter)obj;
2849 cobj.AddCollisionFrameTime(100); 1744 cobj.SendCollisions((int)(odetimestepMS));
2850 cobj.SendCollisions();
2851 break; 1745 break;
2852 1746
2853 case ActorTypes.Prim: 1747 case ActorTypes.Prim:
2854 OdePrim pobj = (OdePrim)obj; 1748 OdePrim pobj = (OdePrim)obj;
2855 pobj.SendCollisions(); 1749 if (!pobj.m_outbounds)
1750 {
1751 pobj.SendCollisions((int)(odetimestepMS));
1752 if(pobj.Body != IntPtr.Zero && !pobj.m_isSelected &&
1753 !pobj.m_disabled && !pobj.m_building &&
1754 !d.BodyIsEnabled(pobj.Body))
1755 sleepers.Add(pobj);
1756 }
2856 break; 1757 break;
2857 } 1758 }
2858 } 1759 }
2859 1760
2860// if (m_global_contactcount > 0) 1761 foreach(OdePrim prm in sleepers)
2861// m_log.DebugFormat( 1762 prm.SleeperAddCollisionEvents();
2862// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); 1763 sleepers.Clear();
2863 1764
2864 m_global_contactcount = 0; 1765 lock(_collisionEventPrimRemove)
2865
2866 if (CollectStats)
2867 { 1766 {
2868 tempTick2 = Util.EnvironmentTickCount(); 1767 foreach (PhysicsActor obj in _collisionEventPrimRemove)
2869 m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1768 _collisionEventPrim.Remove(obj);
2870 tempTick = tempTick2; 1769
1770 _collisionEventPrimRemove.Clear();
2871 } 1771 }
2872 1772
2873 lock(SimulationLock) 1773 // do a ode simulation step
2874 d.WorldQuickStep(world, ODE_STEPSIZE); 1774 d.WorldQuickStep(world, ODE_STEPSIZE);
1775 d.JointGroupEmpty(contactgroup);
2875 1776
2876 if (CollectStats) 1777 // update managed ideia of physical data and do updates to core
2877 m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); 1778 /*
1779 lock (_characters)
1780 {
1781 foreach (OdeCharacter actor in _characters)
1782 {
1783 if (actor != null)
1784 {
1785 if (actor.bad)
1786 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
2878 1787
2879 d.JointGroupEmpty(contactgroup); 1788 actor.UpdatePositionAndVelocity();
1789 }
1790 }
1791 }
1792 */
1793
1794 lock (_activegroups)
1795 {
1796 {
1797 foreach (OdePrim actor in _activegroups)
1798 {
1799 if (actor.IsPhysical)
1800 {
1801 actor.UpdatePositionAndVelocity(framecount);
1802 }
1803 }
1804 }
1805 }
2880 } 1806 }
2881 catch (Exception e) 1807 catch (Exception e)
2882 { 1808 {
2883 m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); 1809 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
1810// ode.dunlock(world);
2884 } 1811 }
2885 1812
2886 step_time -= ODE_STEPSIZE; 1813 step_time -= ODE_STEPSIZE;
2887 fps += ODE_STEPSIZE; 1814 nodeframes++;
2888 }
2889
2890 if (CollectStats)
2891 tempTick = Util.EnvironmentTickCount();
2892 1815
2893 foreach (OdeCharacter actor in _characters) 1816 looptimeMS = Util.EnvironmentTickCountSubtract(loopstartMS);
2894 { 1817 if (looptimeMS > maxLoopTime)
2895 if (actor.bad) 1818 break;
2896 m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
2897
2898 actor.UpdatePositionAndVelocity(defects);
2899 } 1819 }
2900 1820
2901 if (defects.Count != 0) 1821 lock (_badCharacter)
2902 { 1822 {
2903 foreach (OdeCharacter actor in defects) 1823 if (_badCharacter.Count > 0)
2904 { 1824 {
2905 m_log.ErrorFormat( 1825 foreach (OdeCharacter chr in _badCharacter)
2906 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", 1826 {
2907 actor.Name, actor.LocalID, PhysicsSceneName); 1827 RemoveCharacter(chr);
1828 }
2908 1829
2909 RemoveCharacter(actor); 1830 _badCharacter.Clear();
2910 actor.DestroyOdeStructures();
2911 } 1831 }
2912
2913 defects.Clear();
2914 } 1832 }
2915 1833
2916 if (CollectStats) 1834 timedif = now - m_lastMeshExpire;
1835
1836 if (timedif.Seconds > 10)
2917 { 1837 {
2918 tempTick2 = Util.EnvironmentTickCount(); 1838 mesher.ExpireReleaseMeshs();
2919 m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); 1839 m_lastMeshExpire = now;
2920 tempTick = tempTick2;
2921 } 1840 }
2922 1841
2923 //if (timeStep < 0.2f) 1842// information block for in debug breakpoint only
1843/*
1844 int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
1845 int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
1846 int ngroundgeoms = d.SpaceGetNumGeoms(GroundSpace);
1847
1848 int nactivegeoms = 0;
1849 int nactivespaces = 0;
2924 1850
2925 foreach (OdePrim prim in _activeprims) 1851 int nstaticgeoms = 0;
1852 int nstaticspaces = 0;
1853 IntPtr sp;
1854
1855 for (int i = 0; i < ntopactivegeoms; i++)
2926 { 1856 {
2927 if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) 1857 sp = d.SpaceGetGeom(ActiveSpace, i);
1858 if (d.GeomIsSpace(sp))
2928 { 1859 {
2929 prim.UpdatePositionAndVelocity(); 1860 nactivespaces++;
2930 1861 nactivegeoms += d.SpaceGetNumGeoms(sp);
2931 if (SupportsNINJAJoints)
2932 SimulateActorPendingJoints(prim);
2933 } 1862 }
1863 else
1864 nactivegeoms++;
2934 } 1865 }
2935 1866
2936 if (CollectStats) 1867 for (int i = 0; i < ntopstaticgeoms; i++)
2937 m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); 1868 {
1869 sp = d.SpaceGetGeom(StaticSpace, i);
1870 if (d.GeomIsSpace(sp))
1871 {
1872 nstaticspaces++;
1873 nstaticgeoms += d.SpaceGetNumGeoms(sp);
1874 }
1875 else
1876 nstaticgeoms++;
1877 }
2938 1878
2939 //DumpJointInfo(); 1879 int ntopgeoms = d.SpaceGetNumGeoms(TopSpace);
2940 1880
1881 int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray
1882 int nbodies = d.NTotalBodies;
1883 int ngeoms = d.NTotalGeoms;
1884*/
2941 // Finished with all sim stepping. If requested, dump world state to file for debugging. 1885 // Finished with all sim stepping. If requested, dump world state to file for debugging.
2942 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? 1886 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
2943 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? 1887 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
@@ -2956,291 +1900,303 @@ namespace OpenSim.Region.PhysicsModule.ODE
2956 1900
2957 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); 1901 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
2958 } 1902 }
1903
1904 fps = (float)nodeframes * ODE_STEPSIZE / reqTimeStep;
1905
1906 if(step_time < HalfOdeStep)
1907 m_timeDilation = 1.0f;
1908 else if (step_time > m_SkipFramesAtms)
1909 {
1910 // if we lag too much skip frames
1911 m_timeDilation = 0.0f;
1912 step_time = 0;
1913 m_lastframe = DateTime.UtcNow; // skip also the time lost
1914 }
1915 else
1916 {
1917 m_timeDilation = ODE_STEPSIZE / step_time;
1918 if (m_timeDilation > 1)
1919 m_timeDilation = 1;
1920 }
1921 }
1922
1923 return fps;
1924 }
1925
1926 /// <summary>
1927 public override void GetResults()
1928 {
1929 }
1930
1931 public override bool IsThreaded
1932 {
1933 // for now we won't be multithreaded
1934 get { return (false); }
1935 }
1936
1937 public float GetTerrainHeightAtXY(float x, float y)
1938 {
1939 if (TerrainGeom == IntPtr.Zero)
1940 return 0f;
1941
1942 if (TerrainHeightFieldHeight == null || TerrainHeightFieldHeight.Length == 0)
1943 return 0f;
1944
1945 // TerrainHeightField for ODE as offset 1m
1946 x += 1f;
1947 y += 1f;
1948
1949 // make position fit into array
1950 if (x < 0)
1951 x = 0;
1952 if (y < 0)
1953 y = 0;
2959 1954
2960 latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); 1955 // integer indexs
1956 int ix;
1957 int iy;
1958 // interpolators offset
1959 float dx;
1960 float dy;
2961 1961
2962 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics 1962 int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples
2963 // has a max of 100 ms to run theoretically. 1963 int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples
2964 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger. 1964 int regsize = regsizeX;
2965 // If Physics stalls, it takes longer which makes the tick count ms larger.
2966 1965
2967 if (latertickcount < 100) 1966 if (m_OSOdeLib)
1967 {
1968 if (x < regsizeX - 1)
2968 { 1969 {
2969 m_timeDilation = 1.0f; 1970 ix = (int)x;
1971 dx = x - (float)ix;
1972 }
1973 else // out world use external height
1974 {
1975 ix = regsizeX - 2;
1976 dx = 0;
1977 }
1978 if (y < regsizeY - 1)
1979 {
1980 iy = (int)y;
1981 dy = y - (float)iy;
2970 } 1982 }
2971 else 1983 else
2972 { 1984 {
2973 m_timeDilation = 100f / latertickcount; 1985 iy = regsizeY - 2;
2974 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); 1986 dy = 0;
2975 } 1987 }
1988 }
1989 else
1990 {
1991 // we still have square fixed size regions
1992 // also flip x and y because of how map is done for ODE fliped axis
1993 // so ix,iy,dx and dy are inter exchanged
2976 1994
2977 tickCountFrameRun = Util.EnvironmentTickCount(); 1995 regsize = regsizeY;
2978 1996
2979 if (CollectStats) 1997 if (x < regsizeX - 1)
2980 m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); 1998 {
1999 iy = (int)x;
2000 dy = x - (float)iy;
2001 }
2002 else // out world use external height
2003 {
2004 iy = regsizeX - 2;
2005 dy = 0;
2006 }
2007 if (y < regsizeY - 1)
2008 {
2009 ix = (int)y;
2010 dx = y - (float)ix;
2011 }
2012 else
2013 {
2014 ix = regsizeY - 2;
2015 dx = 0;
2016 }
2981 } 2017 }
2982 2018
2983 fps *= 1.0f/timeStep; 2019 float h0;
2984 return fps; 2020 float h1;
2985 } 2021 float h2;
2986 2022
2987 /// <summary> 2023 iy *= regsize;
2988 /// Simulate pending NINJA joints. 2024 iy += ix; // all indexes have iy + ix
2989 /// </summary>
2990 /// <remarks>
2991 /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else.
2992 /// </remarks>
2993 private void SimulatePendingNINJAJoints()
2994 {
2995 // Create pending joints, if possible
2996
2997 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2998 // a joint requires specifying the body id of both involved bodies
2999 if (pendingJoints.Count > 0)
3000 {
3001 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
3002 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
3003 foreach (PhysicsJoint joint in pendingJoints)
3004 {
3005 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
3006 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
3007 List<IntPtr> jointBodies = new List<IntPtr>();
3008 bool allJointBodiesAreReady = true;
3009 foreach (string jointParam in jointParams)
3010 {
3011 if (jointParam == "NULL")
3012 {
3013 //DoJointErrorMessage(joint, "attaching NULL joint to world");
3014 jointBodies.Add(IntPtr.Zero);
3015 }
3016 else
3017 {
3018 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
3019 bool foundPrim = false;
3020 lock (_prims)
3021 {
3022 foreach (OdePrim prim in _prims) // FIXME: inefficient
3023 {
3024 if (prim.SOPName == jointParam)
3025 {
3026 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
3027 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
3028 {
3029 jointBodies.Add(prim.Body);
3030 foundPrim = true;
3031 break;
3032 }
3033 else
3034 {
3035 DoJointErrorMessage(joint, "prim name " + jointParam +
3036 " exists but is not (yet) physical; deferring joint creation. " +
3037 "IsPhysical property is " + prim.IsPhysical +
3038 " and body is " + prim.Body);
3039 foundPrim = false;
3040 break;
3041 }
3042 }
3043 }
3044 }
3045 if (foundPrim)
3046 {
3047 // all is fine
3048 }
3049 else
3050 {
3051 allJointBodiesAreReady = false;
3052 break;
3053 }
3054 }
3055 }
3056 2025
3057 if (allJointBodiesAreReady) 2026 float[] heights = TerrainHeightFieldHeight;
3058 { 2027 /*
3059 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); 2028 if ((dx + dy) <= 1.0f)
3060 if (jointBodies[0] == jointBodies[1])
3061 { 2029 {
3062 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); 2030 h0 = ((float)heights[iy]); // 0,0 vertice
2031 h1 = (((float)heights[iy + 1]) - h0) * dx; // 1,0 vertice minus 0,0
2032 h2 = (((float)heights[iy + regsize]) - h0) * dy; // 0,1 vertice minus 0,0
3063 } 2033 }
3064 else 2034 else
3065 { 2035 {
3066 switch (joint.Type) 2036 h0 = ((float)heights[iy + regsize + 1]); // 1,1 vertice
3067 { 2037 h1 = (((float)heights[iy + 1]) - h0) * (1 - dy); // 1,1 vertice minus 1,0
3068 case PhysicsJointType.Ball: 2038 h2 = (((float)heights[iy + regsize]) - h0) * (1 - dx); // 1,1 vertice minus 0,1
3069 {
3070 IntPtr odeJoint;
3071 //DoJointErrorMessage(joint, "ODE creating ball joint ");
3072 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
3073 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3074 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3075 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
3076 d.JointSetBallAnchor(odeJoint,
3077 joint.Position.X,
3078 joint.Position.Y,
3079 joint.Position.Z);
3080 //DoJointErrorMessage(joint, "ODE joint setting OK");
3081 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
3082 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
3083 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
3084 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
3085
3086 if (joint is OdePhysicsJoint)
3087 {
3088 ((OdePhysicsJoint)joint).jointID = odeJoint;
3089 }
3090 else
3091 {
3092 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3093 }
3094 }
3095 break;
3096 case PhysicsJointType.Hinge:
3097 {
3098 IntPtr odeJoint;
3099 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
3100 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
3101 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3102 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3103 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
3104 d.JointSetHingeAnchor(odeJoint,
3105 joint.Position.X,
3106 joint.Position.Y,
3107 joint.Position.Z);
3108 // We use the orientation of the x-axis of the joint's coordinate frame
3109 // as the axis for the hinge.
3110
3111 // Therefore, we must get the joint's coordinate frame based on the
3112 // joint.Rotation field, which originates from the orientation of the
3113 // joint's proxy object in the scene.
3114
3115 // The joint's coordinate frame is defined as the transformation matrix
3116 // that converts a vector from joint-local coordinates into world coordinates.
3117 // World coordinates are defined as the XYZ coordinate system of the sim,
3118 // as shown in the top status-bar of the viewer.
3119
3120 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
3121 // and use that as the hinge axis.
3122
3123 //joint.Rotation.Normalize();
3124 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
3125
3126 // Now extract the X axis of the joint's coordinate frame.
3127
3128 // Do not try to use proxyFrame.AtAxis or you will become mired in the
3129 // tar pit of transposed, inverted, and generally messed-up orientations.
3130 // (In other words, Matrix4.AtAxis() is borked.)
3131 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
3132
3133 // Instead, compute the X axis of the coordinate frame by transforming
3134 // the (1,0,0) vector. At least that works.
3135
3136 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
3137 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
3138 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
3139 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
3140 d.JointSetHingeAxis(odeJoint,
3141 jointAxis.X,
3142 jointAxis.Y,
3143 jointAxis.Z);
3144 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
3145 if (joint is OdePhysicsJoint)
3146 {
3147 ((OdePhysicsJoint)joint).jointID = odeJoint;
3148 }
3149 else
3150 {
3151 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3152 }
3153 }
3154 break;
3155 }
3156 successfullyProcessedPendingJoints.Add(joint);
3157 } 2039 }
3158 } 2040 */
3159 else 2041 h0 = ((float)heights[iy]); // 0,0 vertice
3160 {
3161 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
3162 }
3163 }
3164 2042
3165 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) 2043 if (dy>dx)
3166 { 2044 {
3167 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); 2045 iy += regsize;
3168 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); 2046 h2 = (float)heights[iy]; // 0,1 vertice
3169 InternalRemovePendingJoint(successfullyProcessedJoint); 2047 h1 = (h2 - h0) * dy; // 0,1 vertice minus 0,0
3170 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); 2048 h2 = ((float)heights[iy + 1] - h2) * dx; // 1,1 vertice minus 0,1
3171 InternalAddActiveJoint(successfullyProcessedJoint);
3172 //DoJointErrorMessage(successfullyProcessedJoint, "done");
3173 }
3174 } 2049 }
2050 else
2051 {
2052 iy++;
2053 h2 = (float)heights[iy]; // vertice 1,0
2054 h1 = (h2 - h0) * dx; // 1,0 vertice minus 0,0
2055 h2 = (((float)heights[iy + regsize]) - h2) * dy; // 1,1 vertice minus 1,0
2056 }
2057
2058 return h0 + h1 + h2;
3175 } 2059 }
3176 2060
3177 /// <summary> 2061 public Vector3 GetTerrainNormalAtXY(float x, float y)
3178 /// Simulate the joint proxies of a NINJA actor.
3179 /// </summary>
3180 /// <remarks>
3181 /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there.
3182 /// </remarks>
3183 /// <param name="actor"></param>
3184 private void SimulateActorPendingJoints(OdePrim actor)
3185 { 2062 {
3186 // If an actor moved, move its joint proxy objects as well. 2063 Vector3 norm = new Vector3(0, 0, 1);
3187 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used 2064
3188 // for this purpose but it is never called! So we just do the joint 2065 if (TerrainGeom == IntPtr.Zero)
3189 // movement code here. 2066 return norm;
2067
2068 if (TerrainHeightFieldHeight == null || TerrainHeightFieldHeight.Length == 0)
2069 return norm;
2070
2071 // TerrainHeightField for ODE as offset 1m
2072 x += 1f;
2073 y += 1f;
2074
2075 // make position fit into array
2076 if (x < 0)
2077 x = 0;
2078 if (y < 0)
2079 y = 0;
3190 2080
3191 if (actor.SOPName != null && 2081 // integer indexs
3192 joints_connecting_actor.ContainsKey(actor.SOPName) && 2082 int ix;
3193 joints_connecting_actor[actor.SOPName] != null && 2083 int iy;
3194 joints_connecting_actor[actor.SOPName].Count > 0) 2084 // interpolators offset
2085 float dx;
2086 float dy;
2087
2088 int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples
2089 int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples
2090 int regsize = regsizeX;
2091
2092 int xstep = 1;
2093 int ystep = regsizeX;
2094 bool firstTri = false;
2095
2096 if (m_OSOdeLib)
3195 { 2097 {
3196 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) 2098 if (x < regsizeX - 1)
3197 { 2099 {
3198 if (affectedJoint.IsInPhysicsEngine) 2100 ix = (int)x;
3199 { 2101 dx = x - (float)ix;
3200 DoJointMoved(affectedJoint); 2102 }
3201 } 2103 else // out world use external height
3202 else 2104 {
3203 { 2105 ix = regsizeX - 2;
3204 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); 2106 dx = 0;
3205 } 2107 }
2108 if (y < regsizeY - 1)
2109 {
2110 iy = (int)y;
2111 dy = y - (float)iy;
2112 }
2113 else
2114 {
2115 iy = regsizeY - 2;
2116 dy = 0;
3206 } 2117 }
2118 firstTri = dy > dx;
3207 } 2119 }
3208 }
3209 2120
3210 public override void GetResults() 2121 else
3211 {
3212 }
3213
3214 public override bool IsThreaded
3215 {
3216 // for now we won't be multithreaded
3217 get { return false; }
3218 }
3219
3220 public override void SetTerrain(float[] heightMap)
3221 {
3222 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3223 { 2122 {
3224 if (m_parentScene is OdeScene) 2123 xstep = regsizeY;
2124 ystep = 1;
2125 regsize = regsizeY;
2126
2127 // we still have square fixed size regions
2128 // also flip x and y because of how map is done for ODE fliped axis
2129 // so ix,iy,dx and dy are inter exchanged
2130 if (x < regsizeX - 1)
3225 { 2131 {
3226 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); 2132 iy = (int)x;
2133 dy = x - (float)iy;
3227 } 2134 }
2135 else // out world use external height
2136 {
2137 iy = regsizeX - 2;
2138 dy = 0;
2139 }
2140 if (y < regsizeY - 1)
2141 {
2142 ix = (int)y;
2143 dx = y - (float)ix;
2144 }
2145 else
2146 {
2147 ix = regsizeY - 2;
2148 dx = 0;
2149 }
2150 firstTri = dx > dy;
2151 }
2152
2153 float h0;
2154 float h1;
2155 float h2;
2156
2157 iy *= regsize;
2158 iy += ix; // all indexes have iy + ix
2159
2160 float[] heights = TerrainHeightFieldHeight;
2161
2162 if (firstTri)
2163 {
2164 h1 = ((float)heights[iy]); // 0,0 vertice
2165 iy += ystep;
2166 h0 = (float)heights[iy]; // 0,1
2167 h2 = (float)heights[iy+xstep]; // 1,1 vertice
2168 norm.X = h0 - h2;
2169 norm.Y = h1 - h0;
3228 } 2170 }
3229 else 2171 else
3230 { 2172 {
3231 SetTerrain(heightMap, m_worldOffset); 2173 h2 = ((float)heights[iy]); // 0,0 vertice
2174 iy += xstep;
2175 h0 = ((float)heights[iy]); // 1,0 vertice
2176 h1 = (float)heights[iy+ystep]; // vertice 1,1
2177 norm.X = h2 - h0;
2178 norm.Y = h0 - h1;
3232 } 2179 }
2180 norm.Z = 1;
2181 norm.Normalize();
2182 return norm;
3233 } 2183 }
3234 2184
3235 private void SetTerrain(float[] heightMap, Vector3 pOffset) 2185 public override void SetTerrain(float[] heightMap)
2186 {
2187 if (m_OSOdeLib)
2188 OSSetTerrain(heightMap);
2189 else
2190 OriSetTerrain(heightMap);
2191 }
2192
2193 public void OriSetTerrain(float[] heightMap)
3236 { 2194 {
3237 int startTime = Util.EnvironmentTickCount(); 2195 // assumes 1m size grid and constante size square regions
3238 m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset); 2196 // needs to know about sims around in future
3239 2197
3240
3241 float[] _heightmap; 2198 float[] _heightmap;
3242 2199
3243 // ok im lasy this are just a aliases
3244 uint regionsizeX = m_regionWidth; 2200 uint regionsizeX = m_regionWidth;
3245 uint regionsizeY = m_regionHeight; 2201 uint regionsizeY = m_regionHeight;
3246 2202
@@ -3258,7 +2214,7 @@ namespace OpenSim.Region.PhysicsModule.ODE
3258 const float thickness = 10f; 2214 const float thickness = 10f;
3259 const int wrap = 0; 2215 const int wrap = 0;
3260 2216
3261 2217
3262 float hfmin = float.MaxValue; 2218 float hfmin = float.MaxValue;
3263 float hfmax = float.MinValue; 2219 float hfmax = float.MinValue;
3264 float val; 2220 float val;
@@ -3267,13 +2223,11 @@ namespace OpenSim.Region.PhysicsModule.ODE
3267 2223
3268 uint maxXX = regionsizeX - 1; 2224 uint maxXX = regionsizeX - 1;
3269 uint maxYY = regionsizeY - 1; 2225 uint maxYY = regionsizeY - 1;
3270
3271 // flipping map adding one margin all around so things don't fall in edges 2226 // flipping map adding one margin all around so things don't fall in edges
3272 2227
3273 uint xt = 0; 2228 uint xt = 0;
3274 xx = 0; 2229 xx = 0;
3275 2230
3276
3277 for (uint x = 0; x < heightmapWidthSamples; x++) 2231 for (uint x = 0; x < heightmapWidthSamples; x++)
3278 { 2232 {
3279 if (x > 1 && xx < maxXX) 2233 if (x > 1 && xx < maxXX)
@@ -3286,7 +2240,7 @@ namespace OpenSim.Region.PhysicsModule.ODE
3286 2240
3287 val = heightMap[yy + xx]; 2241 val = heightMap[yy + xx];
3288 if (val < 0.0f) 2242 if (val < 0.0f)
3289 val = 0.0f; 2243 val = 0.0f; // no neg terrain as in chode
3290 _heightmap[xt + y] = val; 2244 _heightmap[xt + y] = val;
3291 2245
3292 if (hfmin > val) 2246 if (hfmin > val)
@@ -3301,69 +2255,164 @@ namespace OpenSim.Region.PhysicsModule.ODE
3301 { 2255 {
3302 d.AllocateODEDataForThread(~0U); 2256 d.AllocateODEDataForThread(~0U);
3303 2257
3304 IntPtr GroundGeom = IntPtr.Zero; 2258 if (TerrainGeom != IntPtr.Zero)
3305 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3306 { 2259 {
3307 RegionTerrain.Remove(pOffset); 2260 actor_name_map.Remove(TerrainGeom);
3308 if (GroundGeom != IntPtr.Zero) 2261 d.GeomDestroy(TerrainGeom);
3309 {
3310 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3311 {
3312 TerrainHeightFieldHeights.Remove(GroundGeom);
3313 }
3314 d.SpaceRemove(space, GroundGeom);
3315 d.GeomDestroy(GroundGeom);
3316 }
3317 2262
3318 } 2263 }
2264
2265 if (TerrainHeightFieldHeightsHandler.IsAllocated)
2266 TerrainHeightFieldHeightsHandler.Free();
2267
3319 IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); 2268 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3320 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, 2269
3321 heightmapWidth, heightmapHeight, 2270 TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
3322 (int)heightmapWidthSamples, 2271
3323 (int)heightmapHeightSamples, 2272 d.GeomHeightfieldDataBuildSingle(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0,
3324 scale, offset, thickness, wrap); 2273 heightmapHeight, heightmapWidth ,
2274 (int)heightmapHeightSamples, (int)heightmapWidthSamples, scale,
2275 offset, thickness, wrap);
3325 2276
3326 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); 2277 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3327 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); 2278
3328 if (GroundGeom != IntPtr.Zero) 2279 TerrainGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1);
2280
2281 if (TerrainGeom != IntPtr.Zero)
3329 { 2282 {
3330 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); 2283 d.GeomSetCategoryBits(TerrainGeom, (uint)(CollisionCategories.Land));
3331 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); 2284 d.GeomSetCollideBits(TerrainGeom, 0);
2285
2286 PhysicsActor pa = new NullPhysicsActor();
2287 pa.Name = "Terrain";
2288 pa.PhysicsActorType = (int)ActorTypes.Ground;
2289 actor_name_map[TerrainGeom] = pa;
2290
2291// geom_name_map[GroundGeom] = "Terrain";
2292
2293 d.Quaternion q = new d.Quaternion();
2294 q.X = 0.5f;
2295 q.Y = 0.5f;
2296 q.Z = 0.5f;
2297 q.W = 0.5f;
3332 2298
2299 d.GeomSetQuaternion(TerrainGeom, ref q);
2300 d.GeomSetPosition(TerrainGeom, m_regionWidth * 0.5f, m_regionHeight * 0.5f, 0.0f);
2301 TerrainHeightFieldHeight = _heightmap;
3333 } 2302 }
3334 geom_name_map[GroundGeom] = "Terrain"; 2303 else
2304 TerrainHeightFieldHeightsHandler.Free();
2305 }
2306 }
3335 2307
3336 d.Matrix3 R = new d.Matrix3(); 2308 public void OSSetTerrain(float[] heightMap)
2309 {
2310 // assumes 1m size grid and constante size square regions
2311 // needs to know about sims around in future
2312
2313 float[] _heightmap;
3337 2314
3338 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); 2315 uint regionsizeX = m_regionWidth;
3339 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); 2316 uint regionsizeY = m_regionHeight;
2317
2318 uint heightmapWidth = regionsizeX + 2;
2319 uint heightmapHeight = regionsizeY + 2;
2320
2321 uint heightmapWidthSamples = heightmapWidth + 1;
2322 uint heightmapHeightSamples = heightmapHeight + 1;
2323
2324 _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
2325
2326
2327 float hfmin = float.MaxValue;
2328// float hfmax = float.MinValue;
2329 float val;
2330
2331
2332 uint maxXX = regionsizeX - 1;
2333 uint maxYY = regionsizeY - 1;
2334 // adding one margin all around so things don't fall in edges
3340 2335
3341 q1 = q1 * q2; 2336 uint xx;
3342 Vector3 v3; 2337 uint yy = 0;
3343 float angle; 2338 uint yt = 0;
3344 q1.GetAxisAngle(out v3, out angle);
3345 2339
3346 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); 2340 for (uint y = 0; y < heightmapHeightSamples; y++)
3347 d.GeomSetRotation(GroundGeom, ref R); 2341 {
3348 d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0.0f); 2342 if (y > 1 && y < maxYY)
3349 IntPtr testGround = IntPtr.Zero; 2343 yy += regionsizeX;
3350 if (RegionTerrain.TryGetValue(pOffset, out testGround)) 2344 xx = 0;
2345 for (uint x = 0; x < heightmapWidthSamples; x++)
3351 { 2346 {
3352 RegionTerrain.Remove(pOffset); 2347 if (x > 1 && x < maxXX)
2348 xx++;
2349
2350 val = heightMap[yy + xx];
2351 if (val < 0.0f)
2352 val = 0.0f; // no neg terrain as in chode
2353 _heightmap[yt + x] = val;
2354
2355 if (hfmin > val)
2356 hfmin = val;
2357// if (hfmax < val)
2358// hfmax = val;
3353 } 2359 }
3354 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); 2360 yt += heightmapWidthSamples;
3355 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3356 } 2361 }
3357 2362
3358 m_log.DebugFormat( 2363 lock (OdeLock)
3359 "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime)); 2364 {
2365 if (TerrainGeom != IntPtr.Zero)
2366 {
2367 actor_name_map.Remove(TerrainGeom);
2368 d.GeomDestroy(TerrainGeom);
2369 }
2370
2371 if (TerrainHeightFieldHeightsHandler.IsAllocated)
2372 TerrainHeightFieldHeightsHandler.Free();
2373
2374 TerrainHeightFieldHeight = null;
2375
2376 IntPtr HeightmapData = d.GeomOSTerrainDataCreate();
2377
2378 const int wrap = 0;
2379 float thickness = hfmin;
2380 if (thickness < 0)
2381 thickness = 1;
2382
2383 TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
2384
2385 d.GeomOSTerrainDataBuild(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0, 1.0f,
2386 (int)heightmapWidthSamples, (int)heightmapHeightSamples,
2387 thickness, wrap);
2388
2389// d.GeomOSTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
2390 TerrainGeom = d.CreateOSTerrain(GroundSpace, HeightmapData, 1);
2391 if (TerrainGeom != IntPtr.Zero)
2392 {
2393 d.GeomSetCategoryBits(TerrainGeom, (uint)(CollisionCategories.Land));
2394 d.GeomSetCollideBits(TerrainGeom, 0);
2395
2396 PhysicsActor pa = new NullPhysicsActor();
2397 pa.Name = "Terrain";
2398 pa.PhysicsActorType = (int)ActorTypes.Ground;
2399 actor_name_map[TerrainGeom] = pa;
2400
2401// geom_name_map[GroundGeom] = "Terrain";
2402
2403 d.GeomSetPosition(TerrainGeom, m_regionWidth * 0.5f, m_regionHeight * 0.5f, 0.0f);
2404 TerrainHeightFieldHeight = _heightmap;
2405 }
2406 else
2407 TerrainHeightFieldHeightsHandler.Free();
2408 }
3360 } 2409 }
3361 2410
3362 public override void DeleteTerrain() 2411 public override void DeleteTerrain()
3363 { 2412 {
3364 } 2413 }
3365 2414
3366 internal float GetWaterLevel() 2415 public float GetWaterLevel()
3367 { 2416 {
3368 return waterlevel; 2417 return waterlevel;
3369 } 2418 }
@@ -3373,19 +2422,19 @@ namespace OpenSim.Region.PhysicsModule.ODE
3373 waterlevel = baseheight; 2422 waterlevel = baseheight;
3374 } 2423 }
3375 2424
3376 [HandleProcessCorruptedStateExceptions]
3377 public override void Dispose() 2425 public override void Dispose()
3378 { 2426 {
3379 lock(SimulationLock) 2427 lock (OdeLock)
3380 lock(OdeLock)
3381 { 2428 {
3382 if(world == IntPtr.Zero)
3383 return;
3384 2429
3385 _worldInitialized = false; 2430 if (world == IntPtr.Zero)
2431 return;
3386 2432
3387 d.AllocateODEDataForThread(~0U); 2433 d.AllocateODEDataForThread(~0U);
3388 2434
2435 if (m_meshWorker != null)
2436 m_meshWorker.Stop();
2437
3389 if (m_rayCastManager != null) 2438 if (m_rayCastManager != null)
3390 { 2439 {
3391 m_rayCastManager.Dispose(); 2440 m_rayCastManager.Dispose();
@@ -3394,37 +2443,49 @@ namespace OpenSim.Region.PhysicsModule.ODE
3394 2443
3395 lock (_prims) 2444 lock (_prims)
3396 { 2445 {
3397 foreach (OdePrim prm in _prims) 2446 ChangesQueue.Clear();
2447 foreach (OdePrim prm in _prims.Values)
3398 { 2448 {
3399 RemovePrim(prm); 2449 prm.DoAChange(changes.Remove, null);
2450 _collisionEventPrim.Remove(prm);
3400 } 2451 }
2452 _prims.Clear();
3401 } 2453 }
3402 2454
3403 //foreach (OdeCharacter act in _characters) 2455 OdeCharacter[] chtorem;
3404 //{ 2456 lock (_characters)
3405 //RemoveAvatar(act);
3406 //}
3407 IntPtr GroundGeom = IntPtr.Zero;
3408 if (RegionTerrain.TryGetValue(m_worldOffset, out GroundGeom))
3409 { 2457 {
3410 RegionTerrain.Remove(m_worldOffset); 2458 chtorem = new OdeCharacter[_characters.Count];
3411 if (GroundGeom != IntPtr.Zero) 2459 _characters.CopyTo(chtorem);
3412 { 2460 }
3413 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3414 TerrainHeightFieldHeights.Remove(GroundGeom);
3415 d.GeomDestroy(GroundGeom);
3416 }
3417 }
3418 2461
3419 try 2462 ChangesQueue.Clear();
2463 foreach (OdeCharacter ch in chtorem)
2464 ch.DoAChange(changes.Remove, null);
2465
2466 if (TerrainGeom != IntPtr.Zero)
2467 d.GeomDestroy(TerrainGeom);
2468 TerrainGeom = IntPtr.Zero;
2469
2470 if (TerrainHeightFieldHeightsHandler.IsAllocated)
2471 TerrainHeightFieldHeightsHandler.Free();
2472
2473 TerrainHeightFieldHeight = null;
2474
2475 if (ContactgeomsArray != IntPtr.Zero)
3420 { 2476 {
3421 d.WorldDestroy(world); 2477 Marshal.FreeHGlobal(ContactgeomsArray);
3422 world = IntPtr.Zero; 2478 ContactgeomsArray = IntPtr.Zero;
3423 } 2479 }
3424 catch (AccessViolationException e) 2480 if (GlobalContactsArray != IntPtr.Zero)
3425 { 2481 {
3426 m_log.ErrorFormat("[ODE SCENE]: exception {0}", e.Message); 2482 Marshal.FreeHGlobal(GlobalContactsArray);
2483 GlobalContactsArray = IntPtr.Zero;
3427 } 2484 }
2485
2486 d.WorldDestroy(world);
2487 world = IntPtr.Zero;
2488 //d.CloseODE();
3428 } 2489 }
3429 } 2490 }
3430 2491
@@ -3436,17 +2497,13 @@ namespace OpenSim.Region.PhysicsModule.ODE
3436 public override Dictionary<uint, float> GetTopColliders() 2497 public override Dictionary<uint, float> GetTopColliders()
3437 { 2498 {
3438 Dictionary<uint, float> topColliders; 2499 Dictionary<uint, float> topColliders;
2500 List<OdePrim> orderedPrims;
2501 lock (_activeprims)
2502 orderedPrims = new List<OdePrim>(_activeprims);
3439 2503
3440 lock (_prims) 2504 orderedPrims.Sort(compareByCollisionsDesc);
3441 { 2505 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
3442 List<OdePrim> orderedPrims = new List<OdePrim>(_prims); 2506
3443 orderedPrims.Sort(compareByCollisionsDesc);
3444 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
3445
3446 foreach (OdePrim p in _prims)
3447 p.CollisionScore = 0;
3448 }
3449
3450 return topColliders; 2507 return topColliders;
3451 } 2508 }
3452 2509
@@ -3459,7 +2516,16 @@ namespace OpenSim.Region.PhysicsModule.ODE
3459 { 2516 {
3460 if (retMethod != null) 2517 if (retMethod != null)
3461 { 2518 {
3462 m_rayCastManager.QueueRequest(position, direction, length, retMethod); 2519 ODERayRequest req = new ODERayRequest();
2520 req.actor = null;
2521 req.callbackMethod = retMethod;
2522 req.length = length;
2523 req.Normal = direction;
2524 req.Origin = position;
2525 req.Count = 0;
2526 req.filter = RayFilterFlags.AllPrims;
2527
2528 m_rayCastManager.QueueRequest(req);
3463 } 2529 }
3464 } 2530 }
3465 2531
@@ -3467,75 +2533,260 @@ namespace OpenSim.Region.PhysicsModule.ODE
3467 { 2533 {
3468 if (retMethod != null) 2534 if (retMethod != null)
3469 { 2535 {
3470 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); 2536 ODERayRequest req = new ODERayRequest();
2537 req.actor = null;
2538 req.callbackMethod = retMethod;
2539 req.length = length;
2540 req.Normal = direction;
2541 req.Origin = position;
2542 req.Count = Count;
2543 req.filter = RayFilterFlags.AllPrims;
2544
2545 m_rayCastManager.QueueRequest(req);
3471 } 2546 }
3472 } 2547 }
3473 2548
2549
3474 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) 2550 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
3475 { 2551 {
3476 ContactResult[] ourResults = null; 2552 List<ContactResult> ourresults = new List<ContactResult>();
2553 object SyncObject = new object();
2554
3477 RayCallback retMethod = delegate(List<ContactResult> results) 2555 RayCallback retMethod = delegate(List<ContactResult> results)
3478 { 2556 {
3479 ourResults = new ContactResult[results.Count]; 2557 lock (SyncObject)
3480 results.CopyTo(ourResults, 0); 2558 {
2559 ourresults = results;
2560 Monitor.PulseAll(SyncObject);
2561 }
3481 }; 2562 };
3482 int waitTime = 0; 2563
3483 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); 2564 ODERayRequest req = new ODERayRequest();
3484 while (ourResults == null && waitTime < 1000) 2565 req.actor = null;
2566 req.callbackMethod = retMethod;
2567 req.length = length;
2568 req.Normal = direction;
2569 req.Origin = position;
2570 req.Count = Count;
2571 req.filter = RayFilterFlags.AllPrims;
2572
2573 lock (SyncObject)
3485 { 2574 {
3486 Thread.Sleep(1); 2575 m_rayCastManager.QueueRequest(req);
3487 waitTime++; 2576 if (!Monitor.Wait(SyncObject, 500))
2577 return null;
2578 else
2579 return ourresults;
3488 } 2580 }
2581 }
2582
2583 public override bool SupportsRaycastWorldFiltered()
2584 {
2585 return true;
2586 }
2587
2588 public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
2589 {
2590 object SyncObject = new object();
2591 List<ContactResult> ourresults = new List<ContactResult>();
2592
2593 RayCallback retMethod = delegate(List<ContactResult> results)
2594 {
2595 lock (SyncObject)
2596 {
2597 ourresults = results;
2598 Monitor.PulseAll(SyncObject);
2599 }
2600 };
2601
2602 ODERayRequest req = new ODERayRequest();
2603 req.actor = null;
2604 req.callbackMethod = retMethod;
2605 req.length = length;
2606 req.Normal = direction;
2607 req.Origin = position;
2608 req.Count = Count;
2609 req.filter = filter;
2610
2611 lock (SyncObject)
2612 {
2613 m_rayCastManager.QueueRequest(req);
2614 if (!Monitor.Wait(SyncObject, 500))
2615 return null;
2616 else
2617 return ourresults;
2618 }
2619 }
2620
2621 public override List<ContactResult> RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags flags)
2622 {
2623 if (actor == null)
2624 return new List<ContactResult>();
2625
2626 IntPtr geom;
2627 if (actor is OdePrim)
2628 geom = ((OdePrim)actor).prim_geom;
2629 else if (actor is OdeCharacter)
2630 geom = ((OdePrim)actor).prim_geom;
2631 else
2632 return new List<ContactResult>();
2633
2634 if (geom == IntPtr.Zero)
2635 return new List<ContactResult>();
2636
2637 List<ContactResult> ourResults = null;
2638 object SyncObject = new object();
2639
2640 RayCallback retMethod = delegate(List<ContactResult> results)
2641 {
2642 lock (SyncObject)
2643 {
2644 ourResults = results;
2645 Monitor.PulseAll(SyncObject);
2646 }
2647 };
2648
2649 ODERayRequest req = new ODERayRequest();
2650 req.actor = actor;
2651 req.callbackMethod = retMethod;
2652 req.length = length;
2653 req.Normal = direction;
2654 req.Origin = position;
2655 req.Count = Count;
2656 req.filter = flags;
2657
2658 lock (SyncObject)
2659 {
2660 m_rayCastManager.QueueRequest(req);
2661 if (!Monitor.Wait(SyncObject, 500))
2662 return new List<ContactResult>();
2663 }
2664
3489 if (ourResults == null) 2665 if (ourResults == null)
3490 return new List<ContactResult> (); 2666 return new List<ContactResult>();
3491 return new List<ContactResult>(ourResults); 2667 return ourResults;
3492 } 2668 }
3493 2669
3494 public override Dictionary<string, float> GetStats() 2670 public override List<ContactResult> BoxProbe(Vector3 position, Vector3 size, Quaternion orientation, int Count, RayFilterFlags flags)
3495 { 2671 {
3496 if (!CollectStats) 2672 List<ContactResult> ourResults = null;
3497 return null; 2673 object SyncObject = new object();
3498 2674
3499 Dictionary<string, float> returnStats; 2675 ProbeBoxCallback retMethod = delegate(List<ContactResult> results)
2676 {
2677 lock (SyncObject)
2678 {
2679 ourResults = results;
2680 Monitor.PulseAll(SyncObject);
2681 }
2682 };
3500 2683
3501 lock (OdeLock) 2684 ODERayRequest req = new ODERayRequest();
2685 req.actor = null;
2686 req.callbackMethod = retMethod;
2687 req.Normal = size;
2688 req.Origin = position;
2689 req.orientation = orientation;
2690 req.Count = Count;
2691 req.filter = flags;
2692
2693 lock (SyncObject)
2694 {
2695 m_rayCastManager.QueueRequest(req);
2696 if (!Monitor.Wait(SyncObject, 500))
2697 return new List<ContactResult>();
2698 }
2699
2700 if (ourResults == null)
2701 return new List<ContactResult>();
2702 return ourResults;
2703 }
2704
2705 public override List<ContactResult> SphereProbe(Vector3 position, float radius, int Count, RayFilterFlags flags)
2706 {
2707 List<ContactResult> ourResults = null;
2708 object SyncObject = new object();
2709
2710 ProbeSphereCallback retMethod = delegate(List<ContactResult> results)
3502 { 2711 {
3503 returnStats = new Dictionary<string, float>(m_stats); 2712 ourResults = results;
2713 Monitor.PulseAll(SyncObject);
2714 };
2715
2716 ODERayRequest req = new ODERayRequest();
2717 req.actor = null;
2718 req.callbackMethod = retMethod;
2719 req.length = radius;
2720 req.Origin = position;
2721 req.Count = Count;
2722 req.filter = flags;
2723
3504 2724
3505 // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by 2725 lock (SyncObject)
3506 // 3 from the SimStatsReporter. 2726 {
3507 returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; 2727 m_rayCastManager.QueueRequest(req);
3508 returnStats[ODETotalPrimsStatName] = _prims.Count * 3; 2728 if (!Monitor.Wait(SyncObject, 500))
3509 returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; 2729 return new List<ContactResult>();
2730 }
3510 2731
3511 InitializeExtraStats(); 2732 if (ourResults == null)
2733 return new List<ContactResult>();
2734 return ourResults;
2735 }
2736
2737 public override List<ContactResult> PlaneProbe(PhysicsActor actor, Vector4 plane, int Count, RayFilterFlags flags)
2738 {
2739 IntPtr geom = IntPtr.Zero;;
2740
2741 if (actor != null)
2742 {
2743 if (actor is OdePrim)
2744 geom = ((OdePrim)actor).prim_geom;
2745 else if (actor is OdeCharacter)
2746 geom = ((OdePrim)actor).prim_geom;
3512 } 2747 }
3513 2748
3514 returnStats[ODEOtherCollisionFrameMsStatName] 2749 List<ContactResult> ourResults = null;
3515 = returnStats[ODEOtherCollisionFrameMsStatName] 2750 object SyncObject = new object();
3516 - returnStats[ODENativeSpaceCollisionFrameMsStatName]
3517 - returnStats[ODENativeGeomCollisionFrameMsStatName];
3518 2751
3519 return returnStats; 2752 ProbePlaneCallback retMethod = delegate(List<ContactResult> results)
2753 {
2754 ourResults = results;
2755 Monitor.PulseAll(SyncObject);
2756 };
2757
2758 ODERayRequest req = new ODERayRequest();
2759 req.actor = null;
2760 req.callbackMethod = retMethod;
2761 req.length = plane.W;
2762 req.Normal.X = plane.X;
2763 req.Normal.Y = plane.Y;
2764 req.Normal.Z = plane.Z;
2765 req.Count = Count;
2766 req.filter = flags;
2767
2768 lock (SyncObject)
2769 {
2770 m_rayCastManager.QueueRequest(req);
2771 if (!Monitor.Wait(SyncObject, 500))
2772 return new List<ContactResult>();
2773 }
2774
2775 if (ourResults == null)
2776 return new List<ContactResult>();
2777 return ourResults;
3520 } 2778 }
3521 2779
3522 private void InitializeExtraStats() 2780 public override int SitAvatar(PhysicsActor actor, Vector3 AbsolutePosition, Vector3 CameraPosition, Vector3 offset, Vector3 AvatarSize, SitAvatarCallback PhysicsSitResponse)
3523 { 2781 {
3524 m_stats[ODETotalFrameMsStatName] = 0; 2782 Util.FireAndForget( delegate
3525 m_stats[ODEAvatarTaintMsStatName] = 0; 2783 {
3526 m_stats[ODEPrimTaintMsStatName] = 0; 2784 ODESitAvatar sitAvatar = new ODESitAvatar(this, m_rayCastManager);
3527 m_stats[ODEAvatarForcesFrameMsStatName] = 0; 2785 if(sitAvatar != null)
3528 m_stats[ODEPrimForcesFrameMsStatName] = 0; 2786 sitAvatar.Sit(actor, AbsolutePosition, CameraPosition, offset, AvatarSize, PhysicsSitResponse);
3529 m_stats[ODERaycastingFrameMsStatName] = 0; 2787 });
3530 m_stats[ODENativeStepFrameMsStatName] = 0; 2788 return 1;
3531 m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
3532 m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
3533 m_stats[ODEOtherCollisionFrameMsStatName] = 0;
3534 m_stats[ODECollisionNotificationFrameMsStatName] = 0;
3535 m_stats[ODEAvatarContactsStatsName] = 0;
3536 m_stats[ODEPrimContactsStatName] = 0;
3537 m_stats[ODEAvatarUpdateFrameMsStatName] = 0;
3538 m_stats[ODEPrimUpdateFrameMsStatName] = 0;
3539 } 2789 }
2790
3540 } 2791 }
3541} 2792}