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