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