OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
OdeScene.cs
Go to the documentation of this file.
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 // changes for varsize regions
29 // note that raycasts need to have limited range
30 // (even in normal regions)
31 // or application thread stack may just blowup
32 // see RayCast(ODERayCastRequest req)
33 
34 using System;
35 using System.Collections.Generic;
36 using System.Diagnostics;
37 using System.IO;
38 using System.Linq;
39 using System.Reflection;
40 using System.Runtime.ExceptionServices;
41 using System.Runtime.InteropServices;
42 using System.Threading;
43 using log4net;
44 using Nini.Config;
45 using Mono.Addins;
46 using OpenMetaverse;
47 using OpenSim.Framework;
48 using OpenSim.Region.PhysicsModules.SharedBase;
49 using OpenSim.Region.Framework.Scenes;
50 using OpenSim.Region.Framework.Interfaces;
51 
52 namespace OpenSim.Region.PhysicsModule.ODE
53 {
54  public enum StatusIndicators : int
55  {
56  Generic = 0,
57  Start = 1,
58  End = 2
59  }
60 
61  [Flags]
62  public enum CollisionCategories : int
63  {
64  Disabled = 0,
65  Geom = 0x00000001,
66  Body = 0x00000002,
67  Space = 0x00000004,
68  Character = 0x00000008,
69  Land = 0x00000010,
70  Water = 0x00000020,
71  Wind = 0x00000040,
72  Sensor = 0x00000080,
73  Selected = 0x00000100
74  }
75 
79  public enum Material : int
80  {
82  Stone = 0,
84  Metal = 1,
86  Glass = 2,
88  Wood = 3,
90  Flesh = 4,
92  Plastic = 5,
94  Rubber = 6
95  }
96 
97  public class OdeScene : PhysicsScene
98  {
99  private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString());
100 
101  // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
102 
127  internal static Object UniversalColliderSyncObject = new Object();
128  internal static Object SimulationLock = new Object();
129 
133  public bool CollectStats { get; set; }
134 
138  private Dictionary<string, float> m_stats = new Dictionary<string, float>();
139 
143  public const string ODETotalAvatarsStatName = "ODETotalAvatars";
144 
148  public const string ODETotalPrimsStatName = "ODETotalPrims";
149 
153  public const string ODEActivePrimsStatName = "ODEActivePrims";
154 
161  public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
162 
166  public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS";
167 
171  public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS";
172 
176  public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS";
177 
181  public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS";
182 
186  public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS";
187 
191  public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
192 
196  public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
197 
201  public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
202 
206  public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS";
207 
211  public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS";
212 
216  public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS";
217 
221  public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS";
222 
226  public const string ODEAvatarContactsStatsName = "ODEAvatarContacts";
227 
231  public const string ODEPrimContactsStatName = "ODEPrimContacts";
232 
236  private int m_nativeCollisionStartTick;
237 
241  private bool m_inCollisionTiming;
242 
247  private int m_tempAvatarCollisionsThisFrame;
248 
252  private int tickCountFrameRun;
253 
257  private int latertickcount;
258 
259  private Random fluidRandomizer = new Random(Environment.TickCount);
260 
261  public bool m_suportCombine = true;
262 
263  private uint m_regionWidth = Constants.RegionSize;
264  private uint m_regionHeight = Constants.RegionSize;
265 
266  private float ODE_STEPSIZE = 0.0178f;
267  private float metersInSpace = 29.9f;
268  private float m_timeDilation = 1.0f;
269 
270  public float gravityx = 0f;
271  public float gravityy = 0f;
272  public float gravityz = -9.8f;
273 
274  public float AvatarTerminalVelocity { get; set; }
275 
276  private float contactsurfacelayer = 0.001f;
277 
278  private int HashspaceLow = -5;
279  private int HashspaceHigh = 12;
280 
281  private float waterlevel = 0f;
282  private int framecount = 0;
283  //private int m_returncollisions = 10;
284 
285  private IntPtr contactgroup;
286 
287 // internal IntPtr WaterGeom;
288 
289  private float nmTerrainContactFriction = 255.0f;
290  private float nmTerrainContactBounce = 0.1f;
291  private float nmTerrainContactERP = 0.1025f;
292 
293  private float mTerrainContactFriction = 75f;
294  private float mTerrainContactBounce = 0.1f;
295  private float mTerrainContactERP = 0.05025f;
296 
297  private float nmAvatarObjectContactFriction = 250f;
298  private float nmAvatarObjectContactBounce = 0.1f;
299 
300  private float mAvatarObjectContactFriction = 75f;
301  private float mAvatarObjectContactBounce = 0.1f;
302 
303  private float avPIDD = 3200f;
304  private float avPIDP = 1400f;
305  private float avCapRadius = 0.37f;
306  private float avStandupTensor = 2000000f;
307 
314  public bool IsAvCapsuleTilted { get; private set; }
315 
316  private float avDensity = 80f;
317  private float avMovementDivisorWalk = 1.3f;
318  private float avMovementDivisorRun = 0.8f;
319  private float minimumGroundFlightOffset = 3f;
320  public float maximumMassObject = 10000.01f;
321 
322  public bool meshSculptedPrim = true;
323  public bool forceSimplePrimMeshing = false;
324 
325  public float meshSculptLOD = 32;
326  public float MeshSculptphysicalLOD = 16;
327 
328  public float geomDefaultDensity = 10.000006836f;
329 
330  public int geomContactPointsStartthrottle = 3;
331  public int geomUpdatesPerThrottledUpdate = 15;
332  private const int avatarExpectedContacts = 3;
333 
334  public float bodyPIDD = 35f;
335  public float bodyPIDG = 25;
336 
337  public int bodyFramesAutoDisable = 20;
338 
339  private bool m_filterCollisions = true;
340 
341  private d.NearCallback nearCallback;
342  public d.TriCallback triCallback;
343  public d.TriArrayCallback triArrayCallback;
344 
348  private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
349 
353  private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
354 
358  private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
359 
363  private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>();
364 
368  private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
369 
373  private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
374 
378  private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>();
379 
383  private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>();
384 
393  public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
394 
401  public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
402 
409  private readonly List<OdeCharacter> defects = new List<OdeCharacter>();
410 
411  private bool m_NINJA_physics_joints_enabled = false;
412  //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
413  private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
414  private d.ContactGeom[] contacts;
415 
419  private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>();
420 
424  private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>();
425 
429  private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>();
430 
434  private readonly List<string> requestedJointsToBeDeleted = new List<string>();
435 
436  private Object externalJointRequestsLock = new Object();
437  private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
438  private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
439  private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
440  private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
441 
442  private d.Contact contact;
443  private d.Contact TerrainContact;
444  private d.Contact AvatarMovementprimContact;
445  private d.Contact AvatarMovementTerrainContact;
446  private d.Contact WaterContact;
447  private d.Contact[,] m_materialContacts;
448 
449  private int m_physicsiterations = 10;
450  private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
451  private readonly PhysicsActor PANull = new NullPhysicsActor();
452  private float step_time = 0.0f;
453  public IntPtr world;
454  private uint obj2LocalID = 0;
455  private OdeCharacter cc1;
456  private OdePrim cp1;
457  private OdeCharacter cc2;
458  private OdePrim cp2;
459  private int p1ExpectedPoints = 0;
460  private int p2ExpectedPoints = 0;
461 
462  public IntPtr space;
463 
464  // split static geometry collision handling into spaces of 30 meters
465  public IntPtr[,] staticPrimspace;
466 
470  internal Object OdeLock = new Object();
471 
472  private bool _worldInitialized = false;
473 
474  public IMesher mesher;
475 
476  private IConfigSource m_config;
477 
478  public bool physics_logging = false;
479  public int physics_logging_interval = 0;
480  public bool physics_logging_append_existing_logfile = false;
481 
482  private bool avplanted = false;
483  private bool av_av_collisions_off = false;
484 
485  public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
486  public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
487 
488  private volatile int m_global_contactcount = 0;
489 
490  private Vector3 m_worldOffset = Vector3.Zero;
491  public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
492  private PhysicsScene m_parentScene = null;
493 
494  float spacesPerMeterX;
495  float spacesPerMeterY;
496  int spaceGridMaxX;
497  int spaceGridMaxY;
498 
499  private ODERayCastRequestManager m_rayCastManager;
500 
501  public Scene m_frameWorkScene = null;
502 
503  public OdeScene(Scene pscene, IConfigSource psourceconfig, string pname)
504  {
505  m_config = psourceconfig;
506  m_frameWorkScene = pscene;
507 
508  EngineType = pname;
509  PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName;
510 
511  pscene.RegisterModuleInterface<PhysicsScene>(this);
512  Vector3 extent = new Vector3(pscene.RegionInfo.RegionSizeX, pscene.RegionInfo.RegionSizeY, pscene.RegionInfo.RegionSizeZ);
513  Initialise(extent);
514  InitialiseFromConfig(m_config);
515 
516  // This may not be that good since terrain may not be avaiable at this point
517  base.Initialise(pscene.PhysicsRequestAsset,
518  (pscene.Heightmap != null ? pscene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]),
519  (float)pscene.RegionInfo.RegionSettings.WaterHeight);
520 
521  }
522 
523  public void RegionLoaded()
524  {
525  mesher = m_frameWorkScene.RequestModuleInterface<IMesher>();
526  if (mesher == null)
527  m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName);
528 
529  m_frameWorkScene.PhysicsEnabled = true;
530  }
531 
537  private void Initialise(Vector3 regionExtent)
538  {
539  WorldExtents.X = regionExtent.X;
540  m_regionWidth = (uint)regionExtent.X;
541  WorldExtents.Y = regionExtent.Y;
542  m_regionHeight = (uint)regionExtent.Y;
543 
544  m_suportCombine = false;
545 
546  nearCallback = near;
547  m_rayCastManager = new ODERayCastRequestManager(this);
548 
549  // Create the world and the first space
550  world = d.WorldCreate();
551  space = d.HashSpaceCreate(IntPtr.Zero);
552 
553  contactgroup = d.JointGroupCreate(0);
554 
555  d.WorldSetAutoDisableFlag(world, false);
556  }
557 
558  // Initialize from configs
559  private void InitialiseFromConfig(IConfigSource config)
560  {
561  InitializeExtraStats();
562 
563  m_config = config;
564  // Defaults
565 
566  avPIDD = 2200.0f;
567  avPIDP = 900.0f;
568  avStandupTensor = 550000f;
569 
570  int contactsPerCollision = 80;
571 
572  if (m_config != null)
573  {
574  IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
575  if (physicsconfig != null)
576  {
577  CollectStats = physicsconfig.GetBoolean("collect_stats", false);
578 
579  gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
580  gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
581  gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
582 
583  float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f);
584  AvatarTerminalVelocity = Util.Clamp<float>(avatarTerminalVelocity, 0, 255f);
585  if (AvatarTerminalVelocity != avatarTerminalVelocity)
586  {
587  m_log.WarnFormat(
588  "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}",
589  avatarTerminalVelocity, AvatarTerminalVelocity);
590  }
591 
592  HashspaceLow = physicsconfig.GetInt("world_hashspace_level_low", -5);
593  HashspaceHigh = physicsconfig.GetInt("world_hashspace_level_high", 12);
594 
595  metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
596 
597  contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
598 
599  nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
600  nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
601  nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
602 
603  mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
604  mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
605  mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
606 
607  nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
608  nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
609 
610  mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
611  mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
612 
613  ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
614  m_physicsiterations = physicsconfig.GetInt("world_solver_iterations", 10);
615 
616  avDensity = physicsconfig.GetFloat("av_density", 80f);
617 // avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
618  avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
619  avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
620  avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
621  avplanted = physicsconfig.GetBoolean("av_planted", false);
622  av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
623 
624  IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
625 
626  contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
627 
628  geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
629  geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
630 
631  geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
632  bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
633 
634  bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
635  bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
636 
637  forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
638  meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
639  meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
640  MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
641  m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
642 
643  avPIDD = physicsconfig.GetFloat("av_pid_derivative", 2200.0f);
644  avPIDP = physicsconfig.GetFloat("av_pid_proportional", 900.0f);
645  avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor", 550000f);
646 
647  physics_logging = physicsconfig.GetBoolean("physics_logging", false);
648  physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
649  physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
650 
651 // m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
652  minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
653  maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
654  }
655  }
656 
657  contacts = new d.ContactGeom[contactsPerCollision];
658 
659  spacesPerMeterX = 1.0f / metersInSpace;
660  spacesPerMeterY = 1.0f / metersInSpace;
661 
662  spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX);
663  spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY);
664 
665  // note: limit number of spaces
666  if (spaceGridMaxX > 24)
667  {
668  spaceGridMaxX = 24;
669  spacesPerMeterX = spaceGridMaxX / WorldExtents.X;
670  }
671  if (spaceGridMaxY > 24)
672  {
673  spaceGridMaxY = 24;
674  spacesPerMeterY = spaceGridMaxY / WorldExtents.Y;
675  }
676 
677  staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY];
678 
679  // make this index limits
680  spaceGridMaxX--;
681  spaceGridMaxY--;
682 
683  // Centeral contact friction and bounce
684  // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
685  // an avatar falls through in Z but not in X or Y when walking on a prim.
686  contact.surface.mode |= d.ContactFlags.SoftERP;
687  contact.surface.mu = nmAvatarObjectContactFriction;
688  contact.surface.bounce = nmAvatarObjectContactBounce;
689  contact.surface.soft_cfm = 0.010f;
690  contact.surface.soft_erp = 0.010f;
691 
692  // Terrain contact friction and Bounce
693  // This is the *non* moving version. Use this when an avatar
694  // isn't moving to keep it in place better
695  TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
696  TerrainContact.surface.mu = nmTerrainContactFriction;
697  TerrainContact.surface.bounce = nmTerrainContactBounce;
698  TerrainContact.surface.soft_erp = nmTerrainContactERP;
699 
700  WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
701  WaterContact.surface.mu = 0f; // No friction
702  WaterContact.surface.bounce = 0.0f; // No bounce
703  WaterContact.surface.soft_cfm = 0.010f;
704  WaterContact.surface.soft_erp = 0.010f;
705 
706  // Prim contact friction and bounce
707  // THis is the *non* moving version of friction and bounce
708  // Use this when an avatar comes in contact with a prim
709  // and is moving
710  AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
711  AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
712 
713  // Terrain contact friction bounce and various error correcting calculations
714  // Use this when an avatar is in contact with the terrain and moving.
715  AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
716  AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
717  AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
718  AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
719 
720  /*
721  <summary></summary>
722  Stone = 0,
724  Metal = 1,
726  Glass = 2,
728  Wood = 3,
730  Flesh = 4,
732  Plastic = 5,
734  Rubber = 6
735  */
736 
737  m_materialContacts = new d.Contact[7,2];
738 
739  m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
740  m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
741  m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
742  m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
743  m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
744  m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
745 
746  m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
747  m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
748  m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
749  m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
750  m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
751  m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
752 
753  m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
754  m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
755  m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
756  m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
757  m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
758  m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
759 
760  m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
761  m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
762  m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
763  m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
764  m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
765  m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
766 
767  m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
768  m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
769  m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
770  m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
771  m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
772  m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
773 
774  /*
775  private float nmAvatarObjectContactFriction = 250f;
776  private float nmAvatarObjectContactBounce = 0.1f;
777 
778  private float mAvatarObjectContactFriction = 75f;
779  private float mAvatarObjectContactBounce = 0.1f;
780  */
781  m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
782  m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
783  m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
784  m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
785  m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
786  m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
787 
788  m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
789  m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
790  m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
791  m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
792  m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
793  m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
794 
795  m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
796  m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
797  m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
798  m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
799  m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
800  m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
801 
802  m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
803  m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
804  m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
805  m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
806  m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
807  m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
808 
809  m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
810  m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
811  m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
812  m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
813  m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
814  m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
815 
816  m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
817  m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
818  m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
819  m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
820  m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
821  m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
822 
823  m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
824  m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
825  m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
826  m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
827  m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
828  m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
829 
830  m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
831  m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
832  m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
833  m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
834  m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
835  m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
836 
837  m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
838  m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
839  m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
840  m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
841  m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
842  m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
843 
844  d.HashSpaceSetLevels(space, HashspaceLow, HashspaceHigh);
845 
846  // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
847 
848  d.WorldSetGravity(world, gravityx, gravityy, gravityz);
849  d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
850 
851  d.WorldSetLinearDamping(world, 256f);
852  d.WorldSetAngularDamping(world, 256f);
853  d.WorldSetAngularDampingThreshold(world, 256f);
854  d.WorldSetLinearDampingThreshold(world, 256f);
855  d.WorldSetMaxAngularSpeed(world, 256f);
856 
857  d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
858  //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
859 
860  for (int i = 0; i < staticPrimspace.GetLength(0); i++)
861  {
862  for (int j = 0; j < staticPrimspace.GetLength(1); j++)
863  {
864  staticPrimspace[i, j] = IntPtr.Zero;
865  }
866  }
867 
868  _worldInitialized = true;
869  }
870 
871  #region Collision Detection
872 
882  private int CollideGeoms(
883  IntPtr geom1, IntPtr geom2, int maxContacts, d.ContactGeom[] contactsArray, int contactGeomSize)
884  {
885  int count;
886 
887  lock (OdeScene.UniversalColliderSyncObject)
888  {
889  // We do this inside the lock so that we don't count any delay in acquiring it
890  if (CollectStats)
891  m_nativeCollisionStartTick = Util.EnvironmentTickCount();
892 
893  count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
894  }
895 
896  // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably
897  // negligable
898  if (CollectStats)
899  m_stats[ODENativeGeomCollisionFrameMsStatName]
900  += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
901 
902  return count;
903  }
904 
911  private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
912  {
913  if (CollectStats)
914  {
915  m_inCollisionTiming = true;
916  m_nativeCollisionStartTick = Util.EnvironmentTickCount();
917  }
918 
919  d.SpaceCollide2(space1, space2, data, nearCallback);
920 
921  if (CollectStats && m_inCollisionTiming)
922  {
923  m_stats[ODENativeSpaceCollisionFrameMsStatName]
924  += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
925  m_inCollisionTiming = false;
926  }
927  }
928 
935  private void near(IntPtr space, IntPtr g1, IntPtr g2)
936  {
937  if (CollectStats && m_inCollisionTiming)
938  {
939  m_stats[ODENativeSpaceCollisionFrameMsStatName]
940  += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
941  m_inCollisionTiming = false;
942  }
943 
944 // m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
945  // no lock here! It's invoked from within Simulate(), which is thread-locked
946 
947  // Test if we're colliding a geom with a space.
948  // If so we have to drill down into the space recursively
949 
950  if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
951  {
952  if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
953  return;
954 
955  // Separating static prim geometry spaces.
956  // We'll be calling near recursivly if one
957  // of them is a space to find all of the
958  // contact points in the space
959  try
960  {
961  CollideSpaces(g1, g2, IntPtr.Zero);
962  }
963  catch (AccessViolationException)
964  {
965  m_log.Error("[ODE SCENE]: Unable to collide test a space");
966  return;
967  }
968  //Colliding a space or a geom with a space or a geom. so drill down
969 
970  //Collide all geoms in each space..
971  //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
972  //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
973  return;
974  }
975 
976  if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
977  return;
978 
979  IntPtr b1 = d.GeomGetBody(g1);
980  IntPtr b2 = d.GeomGetBody(g2);
981 
982  // d.GeomClassID id = d.GeomGetClass(g1);
983 
984  String name1 = null;
985  String name2 = null;
986 
987  if (!geom_name_map.TryGetValue(g1, out name1))
988  {
989  name1 = "null";
990  }
991  if (!geom_name_map.TryGetValue(g2, out name2))
992  {
993  name2 = "null";
994  }
995 
996  // Figure out how many contact points we have
997  int count = 0;
998 
999  try
1000  {
1001  // Colliding Geom To Geom
1002  // This portion of the function 'was' blatantly ripped off from BoxStack.cs
1003 
1004  if (g1 == g2)
1005  return; // Can't collide with yourself
1006 
1007  if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
1008  return;
1009 
1010  count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.unmanagedSizeOf);
1011 
1012  // All code after this is only relevant if we have any collisions
1013  if (count <= 0)
1014  return;
1015 
1016  if (count > contacts.Length)
1017  m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
1018  }
1019  catch (SEHException)
1020  {
1021  m_log.Error(
1022  "[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.");
1023  base.TriggerPhysicsBasedRestart();
1024  }
1025  catch (Exception e)
1026  {
1027  m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message);
1028  return;
1029  }
1030 
1031  PhysicsActor p1;
1032  PhysicsActor p2;
1033 
1034  p1ExpectedPoints = 0;
1035  p2ExpectedPoints = 0;
1036 
1037  if (!actor_name_map.TryGetValue(g1, out p1))
1038  {
1039  p1 = PANull;
1040  }
1041 
1042  if (!actor_name_map.TryGetValue(g2, out p2))
1043  {
1044  p2 = PANull;
1045  }
1046 
1047  ContactPoint maxDepthContact = new ContactPoint();
1048  if (p1.CollisionScore + count >= float.MaxValue)
1049  p1.CollisionScore = 0;
1050  p1.CollisionScore += count;
1051 
1052  if (p2.CollisionScore + count >= float.MaxValue)
1053  p2.CollisionScore = 0;
1054  p2.CollisionScore += count;
1055 
1056  for (int i = 0; i < count; i++)
1057  {
1058  d.ContactGeom curContact = contacts[i];
1059 
1060  if (curContact.depth > maxDepthContact.PenetrationDepth)
1061  {
1062  maxDepthContact = new ContactPoint(
1063  new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1064  new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1065  curContact.depth
1066  );
1067  }
1068 
1069  //m_log.Warn("[CCOUNT]: " + count);
1070  IntPtr joint;
1071  // If we're colliding with terrain, use 'TerrainContact' instead of contact.
1072  // allows us to have different settings
1073 
1074  // We only need to test p2 for 'jump crouch purposes'
1075  if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
1076  {
1077  // Testing if the collision is at the feet of the avatar
1078 
1079  //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));
1080  if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
1081  p2.IsColliding = true;
1082  }
1083  else
1084  {
1085  p2.IsColliding = true;
1086  }
1087 
1088  //if ((framecount % m_returncollisions) == 0)
1089 
1090  switch (p1.PhysicsActorType)
1091  {
1092  case (int)ActorTypes.Agent:
1093  p1ExpectedPoints = avatarExpectedContacts;
1094  p2.CollidingObj = true;
1095  break;
1096  case (int)ActorTypes.Prim:
1097  if (p1 != null && p1 is OdePrim)
1098  p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1099 
1100  if (p2.Velocity.LengthSquared() > 0.0f)
1101  p2.CollidingObj = true;
1102  break;
1103  case (int)ActorTypes.Unknown:
1104  p2.CollidingGround = true;
1105  break;
1106  default:
1107  p2.CollidingGround = true;
1108  break;
1109  }
1110 
1111  // we don't want prim or avatar to explode
1112 
1113  #region InterPenetration Handling - Unintended physics explosions
1114 
1115  if (curContact.depth >= 0.08f)
1116  {
1117  if (curContact.depth >= 1.00f)
1118  {
1119  //m_log.Info("[P]: " + contact.depth.ToString());
1120  if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1121  p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
1122  (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1123  p2.PhysicsActorType == (int) ActorTypes.Unknown))
1124  {
1125  if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1126  {
1127  if (p2 is OdeCharacter)
1128  {
1129  OdeCharacter character = (OdeCharacter) p2;
1130 
1131  //p2.CollidingObj = true;
1132  curContact.depth = 0.00000003f;
1133  p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
1134  curContact.pos =
1135  new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1136  curContact.pos.Y + (p1.Size.Y/2),
1137  curContact.pos.Z + (p1.Size.Z/2));
1138  character.SetPidStatus(true);
1139  }
1140  }
1141 
1142  if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1143  {
1144  if (p1 is OdeCharacter)
1145  {
1146  OdeCharacter character = (OdeCharacter) p1;
1147 
1148  //p2.CollidingObj = true;
1149  curContact.depth = 0.00000003f;
1150  p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1151  curContact.pos =
1152  new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1153  curContact.pos.Y + (p1.Size.Y/2),
1154  curContact.pos.Z + (p1.Size.Z/2));
1155  character.SetPidStatus(true);
1156  }
1157  }
1158  }
1159  }
1160  }
1161 
1162  #endregion
1163 
1164  // Logic for collision handling
1165  // Note, that if *all* contacts are skipped (VolumeDetect)
1166  // The prim still detects (and forwards) collision events but
1167  // appears to be phantom for the world
1168  Boolean skipThisContact = false;
1169 
1170  if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1171  skipThisContact = true; // No collision on volume detect prims
1172 
1173  if (av_av_collisions_off)
1174  if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1175  skipThisContact = true;
1176 
1177  if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1178  skipThisContact = true; // No collision on volume detect prims
1179 
1180  if (!skipThisContact && curContact.depth < 0f)
1181  skipThisContact = true;
1182 
1183  if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1184  skipThisContact = true;
1185 
1186  const int maxContactsbeforedeath = 4000;
1187  joint = IntPtr.Zero;
1188 
1189  if (!skipThisContact)
1190  {
1191  _perloopContact.Add(curContact);
1192 
1193  if (name1 == "Terrain" || name2 == "Terrain")
1194  {
1195  if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1196  (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1197  {
1198  p2ExpectedPoints = avatarExpectedContacts;
1199  // Avatar is moving on terrain, use the movement terrain contact
1200  AvatarMovementTerrainContact.geom = curContact;
1201 
1202  if (m_global_contactcount < maxContactsbeforedeath)
1203  {
1204  joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1205  m_global_contactcount++;
1206  }
1207  }
1208  else
1209  {
1210  if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1211  {
1212  p2ExpectedPoints = avatarExpectedContacts;
1213  // Avatar is standing on terrain, use the non moving terrain contact
1214  TerrainContact.geom = curContact;
1215 
1216  if (m_global_contactcount < maxContactsbeforedeath)
1217  {
1218  joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1219  m_global_contactcount++;
1220  }
1221  }
1222  else
1223  {
1224  if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1225  {
1226  // prim prim contact
1227  // int pj294950 = 0;
1228  int movintYN = 0;
1229  int material = (int) Material.Wood;
1230  // prim terrain contact
1231  if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1232  {
1233  movintYN = 1;
1234  }
1235 
1236  if (p2 is OdePrim)
1237  {
1238  material = ((OdePrim) p2).m_material;
1239  p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1240  }
1241 
1242  // Unnessesary because p1 is defined above
1243  //if (p1 is OdePrim)
1244  // {
1245  // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1246  // }
1247  //m_log.DebugFormat("Material: {0}", material);
1248 
1249  m_materialContacts[material, movintYN].geom = curContact;
1250 
1251  if (m_global_contactcount < maxContactsbeforedeath)
1252  {
1253  joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1254  m_global_contactcount++;
1255  }
1256  }
1257  else
1258  {
1259  int movintYN = 0;
1260  // prim terrain contact
1261  if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1262  {
1263  movintYN = 1;
1264  }
1265 
1266  int material = (int)Material.Wood;
1267 
1268  if (p2 is OdePrim)
1269  {
1270  material = ((OdePrim)p2).m_material;
1271  p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1272  }
1273 
1274  //m_log.DebugFormat("Material: {0}", material);
1275  m_materialContacts[material, movintYN].geom = curContact;
1276 
1277  if (m_global_contactcount < maxContactsbeforedeath)
1278  {
1279  joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1280  m_global_contactcount++;
1281  }
1282  }
1283  }
1284  }
1285  //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1286  //{
1287  //m_log.Debug("[PHYSICS]: prim contacting with ground");
1288  //}
1289  }
1290  else if (name1 == "Water" || name2 == "Water")
1291  {
1292  /*
1293  if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1294  {
1295  }
1296  else
1297  {
1298  }
1299  */
1300  //WaterContact.surface.soft_cfm = 0.0000f;
1301  //WaterContact.surface.soft_erp = 0.00000f;
1302  if (curContact.depth > 0.1f)
1303  {
1304  curContact.depth *= 52;
1305  //contact.normal = new d.Vector3(0, 0, 1);
1306  //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1307  }
1308 
1309  WaterContact.geom = curContact;
1310 
1311  if (m_global_contactcount < maxContactsbeforedeath)
1312  {
1313  joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1314  m_global_contactcount++;
1315  }
1316  //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1317  }
1318  else
1319  {
1320  if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1321  {
1322  p2ExpectedPoints = avatarExpectedContacts;
1323  if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1324  {
1325  // Avatar is moving on a prim, use the Movement prim contact
1326  AvatarMovementprimContact.geom = curContact;
1327 
1328  if (m_global_contactcount < maxContactsbeforedeath)
1329  {
1330  joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1331  m_global_contactcount++;
1332  }
1333  }
1334  else
1335  {
1336  // Avatar is standing still on a prim, use the non movement contact
1337  contact.geom = curContact;
1338 
1339  if (m_global_contactcount < maxContactsbeforedeath)
1340  {
1341  joint = d.JointCreateContact(world, contactgroup, ref contact);
1342  m_global_contactcount++;
1343  }
1344  }
1345  }
1346  else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1347  {
1348  //p1.PhysicsActorType
1349  int material = (int)Material.Wood;
1350 
1351  if (p2 is OdePrim)
1352  {
1353  material = ((OdePrim)p2).m_material;
1354  p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1355  }
1356 
1357  //m_log.DebugFormat("Material: {0}", material);
1358  m_materialContacts[material, 0].geom = curContact;
1359 
1360  if (m_global_contactcount < maxContactsbeforedeath)
1361  {
1362  joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1363  m_global_contactcount++;
1364  }
1365  }
1366  }
1367 
1368  if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1369  {
1370  d.JointAttach(joint, b1, b2);
1371  m_global_contactcount++;
1372  }
1373  }
1374 
1375  collision_accounting_events(p1, p2, maxDepthContact);
1376 
1377  if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1378  {
1379  // If there are more then 3 contact points, it's likely
1380  // that we've got a pile of objects, so ...
1381  // We don't want to send out hundreds of terse updates over and over again
1382  // so lets throttle them and send them again after it's somewhat sorted out.
1383  p2.ThrottleUpdates = true;
1384  }
1385  //m_log.Debug(count.ToString());
1386  //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1387  }
1388  }
1389 
1390  private bool checkDupe(d.ContactGeom contactGeom, int atype)
1391  {
1392  if (!m_filterCollisions)
1393  return false;
1394 
1395  bool result = false;
1396 
1397  ActorTypes at = (ActorTypes)atype;
1398 
1399  foreach (d.ContactGeom contact in _perloopContact)
1400  {
1401  //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1402  //{
1403  // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1404  if (at == ActorTypes.Agent)
1405  {
1406  if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
1407  && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
1408  && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1409  {
1410  if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1411  {
1412  result = true;
1413  break;
1414  }
1415  }
1416  }
1417  else if (at == ActorTypes.Prim)
1418  {
1419  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)))
1420  {
1421  if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1422  {
1423  if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1424  {
1425  result = true;
1426  break;
1427  }
1428  }
1429  //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1430  //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));
1431  }
1432  }
1433  }
1434 
1435  return result;
1436  }
1437 
1438  private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1439  {
1440  // obj1LocalID = 0;
1441  //returncollisions = false;
1442  obj2LocalID = 0;
1443  //ctype = 0;
1444  //cStartStop = 0;
1445 // if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1446 // return;
1447  bool p1events = p1.SubscribedEvents();
1448  bool p2events = p2.SubscribedEvents();
1449 
1450  if (p1.IsVolumeDtc)
1451  p2events = false;
1452  if (p2.IsVolumeDtc)
1453  p1events = false;
1454 
1455  if (!p2events && !p1events)
1456  return;
1457 
1458  Vector3 vel = Vector3.Zero;
1459  if (p2 != null && p2.IsPhysical)
1460  vel = p2.Velocity;
1461 
1462  if (p1 != null && p1.IsPhysical)
1463  vel -= p1.Velocity;
1464 
1465  contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal);
1466 
1467  switch ((ActorTypes)p2.PhysicsActorType)
1468  {
1469  case ActorTypes.Agent:
1470  cc2 = (OdeCharacter)p2;
1471 
1472  // obj1LocalID = cc2.m_localID;
1473  switch ((ActorTypes)p1.PhysicsActorType)
1474  {
1475  case ActorTypes.Agent:
1476  cc1 = (OdeCharacter)p1;
1477  obj2LocalID = cc1.LocalID;
1478  cc1.AddCollisionEvent(cc2.LocalID, contact);
1479  break;
1480 
1481  case ActorTypes.Prim:
1482  if (p1 is OdePrim)
1483  {
1484  cp1 = (OdePrim) p1;
1485  obj2LocalID = cp1.LocalID;
1486  cp1.AddCollisionEvent(cc2.LocalID, contact);
1487  }
1488  break;
1489 
1490  case ActorTypes.Ground:
1491  case ActorTypes.Unknown:
1492  obj2LocalID = 0;
1493  break;
1494  }
1495 
1496  cc2.AddCollisionEvent(obj2LocalID, contact);
1497  break;
1498 
1499  case ActorTypes.Prim:
1500 
1501  if (p2 is OdePrim)
1502  {
1503  cp2 = (OdePrim) p2;
1504 
1505  // obj1LocalID = cp2.m_localID;
1506  switch ((ActorTypes) p1.PhysicsActorType)
1507  {
1508  case ActorTypes.Agent:
1509  if (p1 is OdeCharacter)
1510  {
1511  cc1 = (OdeCharacter) p1;
1512  obj2LocalID = cc1.LocalID;
1513  cc1.AddCollisionEvent(cp2.LocalID, contact);
1514  }
1515  break;
1516  case ActorTypes.Prim:
1517 
1518  if (p1 is OdePrim)
1519  {
1520  cp1 = (OdePrim) p1;
1521  obj2LocalID = cp1.LocalID;
1522  cp1.AddCollisionEvent(cp2.LocalID, contact);
1523  }
1524  break;
1525 
1526  case ActorTypes.Ground:
1527  case ActorTypes.Unknown:
1528  obj2LocalID = 0;
1529  break;
1530  }
1531 
1532  cp2.AddCollisionEvent(obj2LocalID, contact);
1533  }
1534  break;
1535  }
1536  }
1540  private void collision_optimized()
1541  {
1542  _perloopContact.Clear();
1543 
1544  foreach (OdeCharacter chr in _characters)
1545  {
1546  // Reset the collision values to false
1547  // since we don't know if we're colliding yet
1548  if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1549  continue;
1550 
1551  chr.IsColliding = false;
1552  chr.CollidingGround = false;
1553  chr.CollidingObj = false;
1554 
1555  // Test the avatar's geometry for collision with the space
1556  // This will return near and the space that they are the closest to
1557  // And we'll run this again against the avatar and the space segment
1558  // This will return with a bunch of possible objects in the space segment
1559  // and we'll run it again on all of them.
1560  try
1561  {
1562  CollideSpaces(space, chr.Shell, IntPtr.Zero);
1563  }
1564  catch (AccessViolationException)
1565  {
1566  m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName);
1567  }
1568 
1569  //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1570  //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1571  //{
1572  //chr.Position.Z = terrainheight + 10.0f;
1573  //forcedZ = true;
1574  //}
1575  }
1576 
1577  if (CollectStats)
1578  {
1579  m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
1580  m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
1581  }
1582 
1583  List<OdePrim> removeprims = null;
1584  foreach (OdePrim chr in _activeprims)
1585  {
1586  if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1587  {
1588  try
1589  {
1590  lock (chr)
1591  {
1592  if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1593  {
1594  CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
1595  }
1596  else
1597  {
1598  if (removeprims == null)
1599  {
1600  removeprims = new List<OdePrim>();
1601  }
1602  removeprims.Add(chr);
1603  m_log.Error(
1604  "[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!");
1605  }
1606  }
1607  }
1608  catch (AccessViolationException)
1609  {
1610  m_log.Error("[ODE SCENE]: Unable to space collide");
1611  }
1612  }
1613  }
1614 
1615  if (CollectStats)
1616  m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
1617 
1618  if (removeprims != null)
1619  {
1620  foreach (OdePrim chr in removeprims)
1621  {
1622  _activeprims.Remove(chr);
1623  }
1624  }
1625  }
1626 
1627  #endregion
1628 
1629  public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1630  {
1631  if (!m_suportCombine)
1632  return;
1633  m_worldOffset = offset;
1634  WorldExtents = new Vector2(extents.X, extents.Y);
1635  m_parentScene = pScene;
1636  }
1637 
1638  // Recovered for use by fly height. Kitto Flora
1639  internal float GetTerrainHeightAtXY(float x, float y)
1640  {
1641  IntPtr heightFieldGeom = IntPtr.Zero;
1642  int offsetX = 0;
1643  int offsetY = 0;
1644 
1645  if (m_suportCombine)
1646  {
1647  offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1648  offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1649  }
1650 
1651  if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1652  {
1653  if (heightFieldGeom != IntPtr.Zero)
1654  {
1655  if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1656  {
1657 
1658  int index;
1659 
1660 
1661  if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1662  (int)x < 0.001f || (int)y < 0.001f)
1663  return 0;
1664 
1665  x = x - offsetX + 1f;
1666  y = y - offsetY + 1f;
1667 
1668  // map is rotated
1669  index = (int)x * ((int)m_regionHeight + 3) + (int)y;
1670 
1671  if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1672  {
1673  //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1674  return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1675  }
1676 
1677  else
1678  return 0f;
1679  }
1680  else
1681  {
1682  return 0f;
1683  }
1684 
1685  }
1686  else
1687  {
1688  return 0f;
1689  }
1690 
1691  }
1692  else
1693  {
1694  return 0f;
1695  }
1696  }
1697 // End recovered. Kitto Flora
1698 
1703  internal void AddCollisionEventReporting(PhysicsActor obj)
1704  {
1705 // m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID);
1706 
1707  lock (m_collisionEventActorsChanges)
1708  m_collisionEventActorsChanges[obj.LocalID] = obj;
1709  }
1710 
1715  internal void RemoveCollisionEventReporting(PhysicsActor obj)
1716  {
1717 // m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID);
1718 
1719  lock (m_collisionEventActorsChanges)
1720  m_collisionEventActorsChanges[obj.LocalID] = null;
1721  }
1722 
1723  #region Add/Remove Entities
1724 
1725  public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
1726  {
1727  d.AllocateODEDataForThread(0);
1728 
1729  OdeCharacter newAv
1730  = new OdeCharacter(
1731  avName, this, position, velocity, size, avPIDD, avPIDP,
1732  avCapRadius, avStandupTensor, avDensity,
1733  avMovementDivisorWalk, avMovementDivisorRun);
1734 
1735  newAv.Flying = isFlying;
1736  newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1737  newAv.m_avatarplanted = avplanted;
1738 
1739  return newAv;
1740  }
1741 
1742  public override void RemoveAvatar(PhysicsActor actor)
1743  {
1744 // m_log.DebugFormat(
1745 // "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}",
1746 // actor.Name, actor.LocalID, Name);
1747 
1748  lock (OdeLock)
1749  {
1750  d.AllocateODEDataForThread(0);
1751 
1752  ((OdeCharacter) actor).Destroy();
1753  }
1754  }
1755 
1756  internal void AddCharacter(OdeCharacter chr)
1757  {
1758  chr.m_avatarplanted = avplanted;
1759  if (!_characters.Contains(chr))
1760  {
1761  _characters.Add(chr);
1762 
1763 // m_log.DebugFormat(
1764 // "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}",
1765 // chr.Name, chr.LocalID, Name, _characters.Count);
1766 
1767  if (chr.bad)
1768  m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid);
1769  }
1770  else
1771  {
1772  m_log.ErrorFormat(
1773  "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!",
1774  chr.Name, chr.LocalID);
1775  }
1776  }
1777 
1778  internal void RemoveCharacter(OdeCharacter chr)
1779  {
1780  if (_characters.Contains(chr))
1781  {
1782  _characters.Remove(chr);
1783 
1784 // m_log.DebugFormat(
1785 // "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}",
1786 // chr.Name, chr.LocalID, Name, _characters.Count);
1787  }
1788  else
1789  {
1790  m_log.ErrorFormat(
1791  "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!",
1792  chr.Name, chr.LocalID);
1793  }
1794  }
1795 
1796  private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1797  PrimitiveBaseShape pbs, bool isphysical, uint localID)
1798  {
1799  Vector3 pos = position;
1800  Vector3 siz = size;
1801  Quaternion rot = rotation;
1802 
1803 
1804  OdePrim newPrim;
1805  lock (OdeLock)
1806  {
1807  d.AllocateODEDataForThread(0);
1808  newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical);
1809 
1810  lock (_prims)
1811  _prims.Add(newPrim);
1812  }
1813  newPrim.LocalID = localID;
1814  return newPrim;
1815  }
1816 
1821  internal void ActivatePrim(OdePrim prim)
1822  {
1823  // adds active prim.. (ones that should be iterated over in collisions_optimized
1824  if (!_activeprims.Contains(prim))
1825  _activeprims.Add(prim);
1826  //else
1827  // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1828  }
1829 
1830  public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1831  Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
1832  {
1833 // m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name);
1834 
1835  return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
1836  }
1837 
1838  public override float TimeDilation
1839  {
1840  get { return m_timeDilation; }
1841  }
1842 
1843  public override bool SupportsNINJAJoints
1844  {
1845  get { return m_NINJA_physics_joints_enabled; }
1846  }
1847 
1848  // internal utility function: must be called within a lock (OdeLock)
1849  private void InternalAddActiveJoint(PhysicsJoint joint)
1850  {
1851  activeJoints.Add(joint);
1852  SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1853  }
1854 
1855  // internal utility function: must be called within a lock (OdeLock)
1856  private void InternalAddPendingJoint(OdePhysicsJoint joint)
1857  {
1858  pendingJoints.Add(joint);
1859  SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1860  }
1861 
1862  // internal utility function: must be called within a lock (OdeLock)
1863  private void InternalRemovePendingJoint(PhysicsJoint joint)
1864  {
1865  pendingJoints.Remove(joint);
1866  SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1867  }
1868 
1869  // internal utility function: must be called within a lock (OdeLock)
1870  private void InternalRemoveActiveJoint(PhysicsJoint joint)
1871  {
1872  activeJoints.Remove(joint);
1873  SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1874  }
1875 
1876  public override void DumpJointInfo()
1877  {
1878  string hdr = "[NINJA] JOINTINFO: ";
1879  foreach (PhysicsJoint j in pendingJoints)
1880  {
1881  m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1882  }
1883  m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1884  foreach (string jointName in SOPName_to_pendingJoint.Keys)
1885  {
1886  m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1887  }
1888  m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1889  foreach (PhysicsJoint j in activeJoints)
1890  {
1891  m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1892  }
1893  m_log.Debug(hdr + activeJoints.Count + " total active joints");
1894  foreach (string jointName in SOPName_to_activeJoint.Keys)
1895  {
1896  m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1897  }
1898  m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1899 
1900  m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1901  m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1902  foreach (string actorName in joints_connecting_actor.Keys)
1903  {
1904  m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1905  foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1906  {
1907  m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1908  }
1909  m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1910  }
1911  }
1912 
1913  public override void RequestJointDeletion(string ObjectNameInScene)
1914  {
1915  lock (externalJointRequestsLock)
1916  {
1917  if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1918  {
1919  requestedJointsToBeDeleted.Add(ObjectNameInScene);
1920  }
1921  }
1922  }
1923 
1924  private void DeleteRequestedJoints()
1925  {
1926  List<string> myRequestedJointsToBeDeleted;
1927  lock (externalJointRequestsLock)
1928  {
1929  // make a local copy of the shared list for processing (threading issues)
1930  myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1931  }
1932 
1933  foreach (string jointName in myRequestedJointsToBeDeleted)
1934  {
1935  lock (OdeLock)
1936  {
1937  //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1938  if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1939  {
1940  OdePhysicsJoint joint = null;
1941  if (SOPName_to_activeJoint.ContainsKey(jointName))
1942  {
1943  joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1944  InternalRemoveActiveJoint(joint);
1945  }
1946  else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1947  {
1948  joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1949  InternalRemovePendingJoint(joint);
1950  }
1951 
1952  if (joint != null)
1953  {
1954  //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1955  for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1956  {
1957  string bodyName = joint.BodyNames[iBodyName];
1958  if (bodyName != "NULL")
1959  {
1960  joints_connecting_actor[bodyName].Remove(joint);
1961  if (joints_connecting_actor[bodyName].Count == 0)
1962  {
1963  joints_connecting_actor.Remove(bodyName);
1964  }
1965  }
1966  }
1967 
1968  DoJointDeactivated(joint);
1969  if (joint.jointID != IntPtr.Zero)
1970  {
1971  d.JointDestroy(joint.jointID);
1972  joint.jointID = IntPtr.Zero;
1973  //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1974  }
1975  else
1976  {
1977  //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1978  }
1979  }
1980  else
1981  {
1982  // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1983  }
1984  }
1985  else
1986  {
1987  // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1988  }
1989  }
1990  }
1991 
1992  // remove processed joints from the shared list
1993  lock (externalJointRequestsLock)
1994  {
1995  foreach (string jointName in myRequestedJointsToBeDeleted)
1996  {
1997  requestedJointsToBeDeleted.Remove(jointName);
1998  }
1999  }
2000  }
2001 
2002  // for pending joints we don't know if their associated bodies exist yet or not.
2003  // the joint is actually created during processing of the taints
2004  private void CreateRequestedJoints()
2005  {
2006  List<PhysicsJoint> myRequestedJointsToBeCreated;
2007  lock (externalJointRequestsLock)
2008  {
2009  // make a local copy of the shared list for processing (threading issues)
2010  myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
2011  }
2012 
2013  foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2014  {
2015  lock (OdeLock)
2016  {
2017  if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
2018  {
2019  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);
2020  continue;
2021  }
2022  if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
2023  {
2024  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);
2025  continue;
2026  }
2027 
2028  InternalAddPendingJoint(joint as OdePhysicsJoint);
2029 
2030  if (joint.BodyNames.Count >= 2)
2031  {
2032  for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2033  {
2034  string bodyName = joint.BodyNames[iBodyName];
2035  if (bodyName != "NULL")
2036  {
2037  if (!joints_connecting_actor.ContainsKey(bodyName))
2038  {
2039  joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
2040  }
2041  joints_connecting_actor[bodyName].Add(joint);
2042  }
2043  }
2044  }
2045  }
2046  }
2047 
2048  // remove processed joints from shared list
2049  lock (externalJointRequestsLock)
2050  {
2051  foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2052  {
2053  requestedJointsToBeCreated.Remove(joint);
2054  }
2055  }
2056  }
2057 
2075  string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2076  Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2077  {
2078  OdePhysicsJoint joint = new OdePhysicsJoint();
2079  joint.ObjectNameInScene = objectNameInScene;
2080  joint.Type = jointType;
2081  joint.Position = position;
2082  joint.Rotation = rotation;
2083  joint.RawParams = parms;
2084  joint.BodyNames = new List<string>(bodyNames);
2085  joint.TrackedBodyName = trackedBodyName;
2086  joint.LocalRotation = localRotation;
2087  joint.jointID = IntPtr.Zero;
2088  joint.ErrorMessageCount = 0;
2089 
2090  lock (externalJointRequestsLock)
2091  {
2092  if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2093  {
2094  requestedJointsToBeCreated.Add(joint);
2095  }
2096  }
2097 
2098  return joint;
2099  }
2100 
2101  private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2102  {
2103  //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2104  if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2105  {
2106  List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2107  //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)
2108  foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2109  {
2110  jointsToRemove.Add(j);
2111  }
2112  foreach (PhysicsJoint j in jointsToRemove)
2113  {
2114  //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2115  RequestJointDeletion(j.ObjectNameInScene);
2116  //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2117  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)
2118  }
2119  }
2120  }
2121 
2123  {
2124  //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2125  lock (OdeLock)
2126  {
2127  //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2128  RemoveAllJointsConnectedToActor(actor);
2129  }
2130  }
2131 
2132  // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2133  public override Vector3 GetJointAnchor(PhysicsJoint joint)
2134  {
2135  Debug.Assert(joint.IsInPhysicsEngine);
2136  d.Vector3 pos = new d.Vector3();
2137 
2138  if (!(joint is OdePhysicsJoint))
2139  {
2140  DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2141  }
2142  else
2143  {
2144  OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2145  switch (odeJoint.Type)
2146  {
2147  case PhysicsJointType.Ball:
2148  d.JointGetBallAnchor(odeJoint.jointID, out pos);
2149  break;
2150  case PhysicsJointType.Hinge:
2151  d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2152  break;
2153  }
2154  }
2155  return new Vector3(pos.X, pos.Y, pos.Z);
2156  }
2157 
2169  public override Vector3 GetJointAxis(PhysicsJoint joint)
2170  {
2171  Debug.Assert(joint.IsInPhysicsEngine);
2172  d.Vector3 axis = new d.Vector3();
2173 
2174  if (!(joint is OdePhysicsJoint))
2175  {
2176  DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2177  }
2178  else
2179  {
2180  OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2181  switch (odeJoint.Type)
2182  {
2183  case PhysicsJointType.Ball:
2184  DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2185  break;
2186  case PhysicsJointType.Hinge:
2187  d.JointGetHingeAxis(odeJoint.jointID, out axis);
2188  break;
2189  }
2190  }
2191  return new Vector3(axis.X, axis.Y, axis.Z);
2192  }
2193 
2198  internal void DeactivatePrim(OdePrim prim)
2199  {
2200  _activeprims.Remove(prim);
2201  }
2202 
2203  public override void RemovePrim(PhysicsActor prim)
2204  {
2205  // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
2206  // removed in the next physics simulate pass.
2207  if (prim is OdePrim)
2208  {
2209  lock (OdeLock)
2210  {
2211  OdePrim p = (OdePrim) prim;
2212 
2213  p.setPrimForRemoval();
2214  AddPhysicsActorTaint(prim);
2215  }
2216  }
2217  }
2218 
2231  internal void RemovePrimThreadLocked(OdePrim prim)
2232  {
2233 // m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID);
2234 
2235  lock (prim)
2236  {
2237  RemoveCollisionEventReporting(prim);
2238 
2239  if (prim.prim_geom != IntPtr.Zero)
2240  {
2241  prim.ResetTaints();
2242 
2243  if (prim.IsPhysical)
2244  {
2245  prim.disableBody();
2246  if (prim.childPrim)
2247  {
2248  prim.childPrim = false;
2249  prim.Body = IntPtr.Zero;
2250  prim.m_disabled = true;
2251  prim.IsPhysical = false;
2252  }
2253 
2254 
2255  }
2256  prim.m_targetSpace = IntPtr.Zero;
2257  if (!prim.RemoveGeom())
2258  m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene");
2259 
2260  lock (_prims)
2261  _prims.Remove(prim);
2262 
2263 
2264  if (SupportsNINJAJoints)
2265  RemoveAllJointsConnectedToActorThreadLocked(prim);
2266  }
2267  }
2268  }
2269 
2270  #endregion
2271 
2272  #region Space Separation Calculation
2273 
2278  private void resetSpaceArrayItemToZero(IntPtr pSpace)
2279  {
2280  for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2281  {
2282  for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2283  {
2284  if (staticPrimspace[x, y] == pSpace)
2285  staticPrimspace[x, y] = IntPtr.Zero;
2286  }
2287  }
2288  }
2289 
2290 // private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2291 // {
2292 // staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2293 // }
2294 
2302  internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2303  {
2304  // Called from setting the Position and Size of an ODEPrim so
2305  // it's already in locked space.
2306 
2307  // we don't want to remove the main space
2308  // we don't need to test physical here because this function should
2309  // never be called if the prim is physical(active)
2310 
2311  // All physical prim end up in the root space
2312  //Thread.Sleep(20);
2313  if (currentspace != space)
2314  {
2315  //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2316  //if (currentspace == IntPtr.Zero)
2317  //{
2318  //int adfadf = 0;
2319  //}
2320  if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2321  {
2322  if (d.GeomIsSpace(currentspace))
2323  {
2324 // waitForSpaceUnlock(currentspace);
2325  d.SpaceRemove(currentspace, geom);
2326  }
2327  else
2328  {
2329  m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2330  " Geom:" + geom);
2331  }
2332  }
2333  else
2334  {
2335  IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2336  if (sGeomIsIn != IntPtr.Zero)
2337  {
2338  if (d.GeomIsSpace(currentspace))
2339  {
2340 // waitForSpaceUnlock(sGeomIsIn);
2341  d.SpaceRemove(sGeomIsIn, geom);
2342  }
2343  else
2344  {
2345  m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2346  sGeomIsIn + " Geom:" + geom);
2347  }
2348  }
2349  }
2350 
2351  //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2352  if (d.SpaceGetNumGeoms(currentspace) == 0)
2353  {
2354  if (currentspace != IntPtr.Zero)
2355  {
2356  if (d.GeomIsSpace(currentspace))
2357  {
2358  d.SpaceRemove(space, currentspace);
2359  // free up memory used by the space.
2360 
2361  resetSpaceArrayItemToZero(currentspace);
2362  }
2363  else
2364  {
2365  m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2366  currentspace + " Geom:" + geom);
2367  }
2368  }
2369  }
2370  }
2371  else
2372  {
2373  // this is a physical object that got disabled. ;.;
2374  if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2375  {
2376  if (d.SpaceQuery(currentspace, geom))
2377  {
2378  if (d.GeomIsSpace(currentspace))
2379  {
2380 // waitForSpaceUnlock(currentspace);
2381  d.SpaceRemove(currentspace, geom);
2382  }
2383  else
2384  {
2385  m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2386  currentspace + " Geom:" + geom);
2387  }
2388  }
2389  else
2390  {
2391  IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2392  if (sGeomIsIn != IntPtr.Zero)
2393  {
2394  if (d.GeomIsSpace(sGeomIsIn))
2395  {
2396 // waitForSpaceUnlock(sGeomIsIn);
2397  d.SpaceRemove(sGeomIsIn, geom);
2398  }
2399  else
2400  {
2401  m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2402  sGeomIsIn + " Geom:" + geom);
2403  }
2404  }
2405  }
2406  }
2407  }
2408 
2409  // The routines in the Position and Size sections do the 'inserting' into the space,
2410  // so all we have to do is make sure that the space that we're putting the prim into
2411  // is in the 'main' space.
2412  int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2413  IntPtr newspace = calculateSpaceForGeom(pos);
2414 
2415  if (newspace == IntPtr.Zero)
2416  {
2417  newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2418  d.HashSpaceSetLevels(newspace, HashspaceLow, HashspaceHigh);
2419  }
2420 
2421  return newspace;
2422  }
2423 
2430  internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2431  {
2432  // creating a new space for prim and inserting it into main space.
2433  staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2434  d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2435 // waitForSpaceUnlock(space);
2436  d.SpaceSetSublevel(space, 1);
2437  d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2438 
2439  return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2440  }
2441 
2447  internal IntPtr calculateSpaceForGeom(Vector3 pos)
2448  {
2449  int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2450  //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2451  return staticPrimspace[xyspace[0], xyspace[1]];
2452  }
2453 
2459  internal int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2460  {
2461  int[] returnint = new int[2];
2462 
2463  returnint[0] = (int) (pos.X * spacesPerMeterX);
2464 
2465  if (returnint[0] > spaceGridMaxX)
2466  returnint[0] = spaceGridMaxX;
2467  if (returnint[0] < 0)
2468  returnint[0] = 0;
2469 
2470  returnint[1] = (int)(pos.Y * spacesPerMeterY);
2471  if (returnint[1] > spaceGridMaxY)
2472  returnint[1] = spaceGridMaxY;
2473  if (returnint[1] < 0)
2474  returnint[1] = 0;
2475 
2476  return returnint;
2477  }
2478 
2479  #endregion
2480 
2486  internal bool needsMeshing(PrimitiveBaseShape pbs)
2487  {
2488  // most of this is redundant now as the mesher will return null if it cant mesh a prim
2489  // but we still need to check for sculptie meshing being enabled so this is the most
2490  // convenient place to do it for now...
2491 
2492  // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2493  // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2494  int iPropertiesNotSupportedDefault = 0;
2495 
2496  if (pbs.SculptEntry && !meshSculptedPrim)
2497  {
2498 #if SPAM
2499  m_log.Warn("NonMesh");
2500 #endif
2501  return false;
2502  }
2503 
2504  // 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
2505  if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2506  {
2507  if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2508  || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2509  && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2510  {
2511 
2512  if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2513  && pbs.ProfileHollow == 0
2514  && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2515  && pbs.PathBegin == 0 && pbs.PathEnd == 0
2516  && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2517  && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2518  && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2519  {
2520 #if SPAM
2521  m_log.Warn("NonMesh");
2522 #endif
2523  return false;
2524  }
2525  }
2526  }
2527 
2528  if (pbs.ProfileHollow != 0)
2529  iPropertiesNotSupportedDefault++;
2530 
2531  if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2532  iPropertiesNotSupportedDefault++;
2533 
2534  if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2535  iPropertiesNotSupportedDefault++;
2536 
2537  if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2538  iPropertiesNotSupportedDefault++;
2539 
2540  if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2541  iPropertiesNotSupportedDefault++;
2542 
2543  if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2544  iPropertiesNotSupportedDefault++;
2545 
2546  if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2547  iPropertiesNotSupportedDefault++;
2548 
2549  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))
2550  iPropertiesNotSupportedDefault++;
2551 
2552  if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2553  iPropertiesNotSupportedDefault++;
2554 
2555  // test for torus
2556  if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2557  {
2558  if (pbs.PathCurve == (byte)Extrusion.Curve1)
2559  {
2560  iPropertiesNotSupportedDefault++;
2561  }
2562  }
2563  else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2564  {
2565  if (pbs.PathCurve == (byte)Extrusion.Straight)
2566  {
2567  iPropertiesNotSupportedDefault++;
2568  }
2569 
2570  // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2571  else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2572  {
2573  iPropertiesNotSupportedDefault++;
2574  }
2575  }
2576  else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2577  {
2578  if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2579  {
2580  iPropertiesNotSupportedDefault++;
2581  }
2582  }
2583  else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2584  {
2585  if (pbs.PathCurve == (byte)Extrusion.Straight)
2586  {
2587  iPropertiesNotSupportedDefault++;
2588  }
2589  else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2590  {
2591  iPropertiesNotSupportedDefault++;
2592  }
2593  }
2594 
2595  if (pbs.SculptEntry && meshSculptedPrim)
2596  iPropertiesNotSupportedDefault++;
2597 
2598  if (iPropertiesNotSupportedDefault == 0)
2599  {
2600 #if SPAM
2601  m_log.Warn("NonMesh");
2602 #endif
2603  return false;
2604  }
2605 #if SPAM
2606  m_log.Debug("Mesh");
2607 #endif
2608  return true;
2609  }
2610 
2619  public override void AddPhysicsActorTaint(PhysicsActor actor)
2620  {
2621  if (actor is OdePrim)
2622  {
2623  OdePrim taintedprim = ((OdePrim)actor);
2624  lock (_taintedPrims)
2625  _taintedPrims.Add(taintedprim);
2626  }
2627  else if (actor is OdeCharacter)
2628  {
2629  OdeCharacter taintedchar = ((OdeCharacter)actor);
2630  lock (_taintedActors)
2631  {
2632  _taintedActors.Add(taintedchar);
2633  if (taintedchar.bad)
2634  m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2635  }
2636  }
2637  }
2638 
2639  // does all pending changes generated during region load process
2640  public override void ProcessPreSimulation()
2641  {
2642  lock (OdeLock)
2643  {
2644  if (world == IntPtr.Zero)
2645  {
2646  _taintedPrims.Clear();;
2647  return;
2648  }
2649 
2650  int donechanges = 0;
2651  if (_taintedPrims.Count > 0)
2652  {
2653 
2654  m_log.InfoFormat("[Ode] start processing pending actor operations");
2655  int tstart = Util.EnvironmentTickCount();
2656 
2657  d.AllocateODEDataForThread(0);
2658 
2659  lock (_taintedPrims)
2660  {
2661  foreach (OdePrim prim in _taintedPrims)
2662  {
2663  if (prim.m_taintremove)
2664  RemovePrimThreadLocked(prim);
2665  else
2666  prim.ProcessTaints();
2667 
2668  prim.m_collisionscore = 0;
2669  donechanges++;
2670  }
2671  _taintedPrims.Clear();
2672  }
2673 
2674  int time = Util.EnvironmentTickCountSubtract(tstart);
2675  m_log.InfoFormat("[Ode] finished {0} operations in {1}ms", donechanges, time);
2676  }
2677  m_log.InfoFormat("[Ode] {0} prim actors loaded",_prims.Count);
2678  }
2679  }
2680 
2681 
2693  public override float Simulate(float timeStep)
2694  {
2695  if (!_worldInitialized)
2696  return 1.0f;
2697 
2698  int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
2699  int tempTick = 0, tempTick2 = 0;
2700 
2701  if (framecount >= int.MaxValue)
2702  framecount = 0;
2703 
2704  framecount++;
2705 
2706  float fps = 0;
2707 
2708  step_time += timeStep;
2709 
2710  float HalfOdeStep = ODE_STEPSIZE * 0.5f;
2711  if (step_time < HalfOdeStep)
2712  return 0;
2713 
2714 
2715  // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential
2716  // deadlock if the collision event tries to lock something else later on which is already locked by a
2717  // caller that is adding or removing the collision event.
2718  lock (m_collisionEventActorsChanges)
2719  {
2720  foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges)
2721  {
2722  if (kvp.Value == null)
2723  m_collisionEventActors.Remove(kvp.Key);
2724  else
2725  m_collisionEventActors[kvp.Key] = kvp.Value;
2726  }
2727 
2728  m_collisionEventActorsChanges.Clear();
2729  }
2730 
2731  if (SupportsNINJAJoints)
2732  {
2733  DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2734  CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2735  }
2736 
2737 
2738  lock (OdeLock)
2739  {
2740  d.AllocateODEDataForThread(~0U);
2741 
2742  while (step_time > HalfOdeStep)
2743  {
2744  try
2745  {
2746  if (CollectStats)
2747  tempTick = Util.EnvironmentTickCount();
2748 
2749  lock (_taintedActors)
2750  {
2751  foreach (OdeCharacter character in _taintedActors)
2752  character.ProcessTaints();
2753 
2754  _taintedActors.Clear();
2755  }
2756 
2757  if (CollectStats)
2758  {
2759  tempTick2 = Util.EnvironmentTickCount();
2760  m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2761  tempTick = tempTick2;
2762  }
2763 
2764  lock (_taintedPrims)
2765  {
2766  foreach (OdePrim prim in _taintedPrims)
2767  {
2768  if (prim.m_taintremove)
2769  {
2770 // Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name);
2771  RemovePrimThreadLocked(prim);
2772  }
2773  else
2774  {
2775 // Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name);
2776  prim.ProcessTaints();
2777  }
2778 
2779  prim.m_collisionscore = 0;
2780 
2781  // This loop can block up the Heartbeat for a very long time on large regions.
2782  // We need to let the Watchdog know that the Heartbeat is not dead
2783  // NOTE: This is currently commented out, but if things like OAR loading are
2784  // timing the heartbeat out we will need to uncomment it
2785  //Watchdog.UpdateThread();
2786  }
2787 
2788  if (SupportsNINJAJoints)
2789  SimulatePendingNINJAJoints();
2790 
2791  _taintedPrims.Clear();
2792  }
2793 
2794  if (CollectStats)
2795  {
2796  tempTick2 = Util.EnvironmentTickCount();
2797  m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2798  tempTick = tempTick2;
2799  }
2800 
2801  // Move characters
2802  foreach (OdeCharacter actor in _characters)
2803  actor.Move(defects);
2804 
2805  if (defects.Count != 0)
2806  {
2807  foreach (OdeCharacter actor in defects)
2808  {
2809  m_log.ErrorFormat(
2810  "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving",
2811  actor.Name, actor.LocalID, PhysicsSceneName);
2812 
2813  RemoveCharacter(actor);
2814  actor.DestroyOdeStructures();
2815  }
2816 
2817  defects.Clear();
2818  }
2819 
2820  if (CollectStats)
2821  {
2822  tempTick2 = Util.EnvironmentTickCount();
2823  m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2824  tempTick = tempTick2;
2825  }
2826 
2827  // Move other active objects
2828  foreach (OdePrim prim in _activeprims)
2829  {
2830  prim.m_collisionscore = 0;
2831  prim.Move(timeStep);
2832  }
2833 
2834  if (CollectStats)
2835  {
2836  tempTick2 = Util.EnvironmentTickCount();
2837  m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2838  tempTick = tempTick2;
2839  }
2840 
2841  m_rayCastManager.ProcessQueuedRequests();
2842 
2843  if (CollectStats)
2844  {
2845  tempTick2 = Util.EnvironmentTickCount();
2846  m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2847  tempTick = tempTick2;
2848  }
2849 
2850  collision_optimized();
2851 
2852  if (CollectStats)
2853  {
2854  tempTick2 = Util.EnvironmentTickCount();
2855  m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2856  tempTick = tempTick2;
2857  }
2858 
2859  foreach (PhysicsActor obj in m_collisionEventActors.Values)
2860  {
2861  // m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID);
2862 
2863  switch ((ActorTypes)obj.PhysicsActorType)
2864  {
2865  case ActorTypes.Agent:
2866  OdeCharacter cobj = (OdeCharacter)obj;
2867  cobj.AddCollisionFrameTime(100);
2868  cobj.SendCollisions();
2869  break;
2870 
2871  case ActorTypes.Prim:
2872  OdePrim pobj = (OdePrim)obj;
2873  pobj.SendCollisions();
2874  break;
2875  }
2876  }
2877 
2878 // if (m_global_contactcount > 0)
2879 // m_log.DebugFormat(
2880 // "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
2881 
2882  m_global_contactcount = 0;
2883 
2884  if (CollectStats)
2885  {
2886  tempTick2 = Util.EnvironmentTickCount();
2887  m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2888  tempTick = tempTick2;
2889  }
2890 
2891  lock(SimulationLock)
2892  d.WorldQuickStep(world, ODE_STEPSIZE);
2893 
2894  if (CollectStats)
2895  m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
2896 
2897  d.JointGroupEmpty(contactgroup);
2898  }
2899  catch (Exception e)
2900  {
2901  m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
2902  }
2903 
2904  step_time -= ODE_STEPSIZE;
2905  fps += ODE_STEPSIZE;
2906  }
2907 
2908  if (CollectStats)
2909  tempTick = Util.EnvironmentTickCount();
2910 
2911  foreach (OdeCharacter actor in _characters)
2912  {
2913  if (actor.bad)
2914  m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
2915 
2916  actor.UpdatePositionAndVelocity(defects);
2917  }
2918 
2919  if (defects.Count != 0)
2920  {
2921  foreach (OdeCharacter actor in defects)
2922  {
2923  m_log.ErrorFormat(
2924  "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity",
2925  actor.Name, actor.LocalID, PhysicsSceneName);
2926 
2927  RemoveCharacter(actor);
2928  actor.DestroyOdeStructures();
2929  }
2930 
2931  defects.Clear();
2932  }
2933 
2934  if (CollectStats)
2935  {
2936  tempTick2 = Util.EnvironmentTickCount();
2937  m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
2938  tempTick = tempTick2;
2939  }
2940 
2941  //if (timeStep < 0.2f)
2942 
2943  foreach (OdePrim prim in _activeprims)
2944  {
2945  if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag))
2946  {
2947  prim.UpdatePositionAndVelocity();
2948 
2949  if (SupportsNINJAJoints)
2950  SimulateActorPendingJoints(prim);
2951  }
2952  }
2953 
2954  if (CollectStats)
2955  m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
2956 
2957  //DumpJointInfo();
2958 
2959  // Finished with all sim stepping. If requested, dump world state to file for debugging.
2960  // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
2961  // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
2962  if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
2963  {
2964  string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
2965  string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
2966 
2967  if (physics_logging_append_existing_logfile)
2968  {
2969  string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
2970  TextWriter fwriter = File.AppendText(fname);
2971  fwriter.WriteLine(header);
2972  fwriter.Close();
2973  }
2974 
2975  d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
2976  }
2977 
2978  latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun);
2979 
2980  // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
2981  // has a max of 100 ms to run theoretically.
2982  // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
2983  // If Physics stalls, it takes longer which makes the tick count ms larger.
2984 
2985  if (latertickcount < 100)
2986  {
2987  m_timeDilation = 1.0f;
2988  }
2989  else
2990  {
2991  m_timeDilation = 100f / latertickcount;
2992  //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
2993  }
2994 
2995  tickCountFrameRun = Util.EnvironmentTickCount();
2996 
2997  if (CollectStats)
2998  m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
2999  }
3000 
3001  fps *= 1.0f/timeStep;
3002  return fps;
3003  }
3004 
3011  private void SimulatePendingNINJAJoints()
3012  {
3013  // Create pending joints, if possible
3014 
3015  // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
3016  // a joint requires specifying the body id of both involved bodies
3017  if (pendingJoints.Count > 0)
3018  {
3019  List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
3020  //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
3021  foreach (PhysicsJoint joint in pendingJoints)
3022  {
3023  //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
3024  string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
3025  List<IntPtr> jointBodies = new List<IntPtr>();
3026  bool allJointBodiesAreReady = true;
3027  foreach (string jointParam in jointParams)
3028  {
3029  if (jointParam == "NULL")
3030  {
3031  //DoJointErrorMessage(joint, "attaching NULL joint to world");
3032  jointBodies.Add(IntPtr.Zero);
3033  }
3034  else
3035  {
3036  //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
3037  bool foundPrim = false;
3038  lock (_prims)
3039  {
3040  foreach (OdePrim prim in _prims) // FIXME: inefficient
3041  {
3042  if (prim.SOPName == jointParam)
3043  {
3044  //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
3045  if (prim.IsPhysical && prim.Body != IntPtr.Zero)
3046  {
3047  jointBodies.Add(prim.Body);
3048  foundPrim = true;
3049  break;
3050  }
3051  else
3052  {
3053  DoJointErrorMessage(joint, "prim name " + jointParam +
3054  " exists but is not (yet) physical; deferring joint creation. " +
3055  "IsPhysical property is " + prim.IsPhysical +
3056  " and body is " + prim.Body);
3057  foundPrim = false;
3058  break;
3059  }
3060  }
3061  }
3062  }
3063  if (foundPrim)
3064  {
3065  // all is fine
3066  }
3067  else
3068  {
3069  allJointBodiesAreReady = false;
3070  break;
3071  }
3072  }
3073  }
3074 
3075  if (allJointBodiesAreReady)
3076  {
3077  //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
3078  if (jointBodies[0] == jointBodies[1])
3079  {
3080  DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
3081  }
3082  else
3083  {
3084  switch (joint.Type)
3085  {
3086  case PhysicsJointType.Ball:
3087  {
3088  IntPtr odeJoint;
3089  //DoJointErrorMessage(joint, "ODE creating ball joint ");
3090  odeJoint = d.JointCreateBall(world, IntPtr.Zero);
3091  //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3092  d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3093  //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
3094  d.JointSetBallAnchor(odeJoint,
3095  joint.Position.X,
3096  joint.Position.Y,
3097  joint.Position.Z);
3098  //DoJointErrorMessage(joint, "ODE joint setting OK");
3099  //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
3100  //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
3101  //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
3102  //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
3103 
3104  if (joint is OdePhysicsJoint)
3105  {
3106  ((OdePhysicsJoint)joint).jointID = odeJoint;
3107  }
3108  else
3109  {
3110  DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3111  }
3112  }
3113  break;
3114  case PhysicsJointType.Hinge:
3115  {
3116  IntPtr odeJoint;
3117  //DoJointErrorMessage(joint, "ODE creating hinge joint ");
3118  odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
3119  //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3120  d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3121  //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
3122  d.JointSetHingeAnchor(odeJoint,
3123  joint.Position.X,
3124  joint.Position.Y,
3125  joint.Position.Z);
3126  // We use the orientation of the x-axis of the joint's coordinate frame
3127  // as the axis for the hinge.
3128 
3129  // Therefore, we must get the joint's coordinate frame based on the
3130  // joint.Rotation field, which originates from the orientation of the
3131  // joint's proxy object in the scene.
3132 
3133  // The joint's coordinate frame is defined as the transformation matrix
3134  // that converts a vector from joint-local coordinates into world coordinates.
3135  // World coordinates are defined as the XYZ coordinate system of the sim,
3136  // as shown in the top status-bar of the viewer.
3137 
3138  // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
3139  // and use that as the hinge axis.
3140 
3141  //joint.Rotation.Normalize();
3142  Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
3143 
3144  // Now extract the X axis of the joint's coordinate frame.
3145 
3146  // Do not try to use proxyFrame.AtAxis or you will become mired in the
3147  // tar pit of transposed, inverted, and generally messed-up orientations.
3148  // (In other words, Matrix4.AtAxis() is borked.)
3149  // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
3150 
3151  // Instead, compute the X axis of the coordinate frame by transforming
3152  // the (1,0,0) vector. At least that works.
3153 
3154  //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
3155  Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
3156  //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
3157  //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
3158  d.JointSetHingeAxis(odeJoint,
3159  jointAxis.X,
3160  jointAxis.Y,
3161  jointAxis.Z);
3162  //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
3163  if (joint is OdePhysicsJoint)
3164  {
3165  ((OdePhysicsJoint)joint).jointID = odeJoint;
3166  }
3167  else
3168  {
3169  DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3170  }
3171  }
3172  break;
3173  }
3174  successfullyProcessedPendingJoints.Add(joint);
3175  }
3176  }
3177  else
3178  {
3179  DoJointErrorMessage(joint, "joint could not yet be created; still pending");
3180  }
3181  }
3182 
3183  foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
3184  {
3185  //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
3186  //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
3187  InternalRemovePendingJoint(successfullyProcessedJoint);
3188  //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
3189  InternalAddActiveJoint(successfullyProcessedJoint);
3190  //DoJointErrorMessage(successfullyProcessedJoint, "done");
3191  }
3192  }
3193  }
3194 
3202  private void SimulateActorPendingJoints(OdePrim actor)
3203  {
3204  // If an actor moved, move its joint proxy objects as well.
3205  // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3206  // for this purpose but it is never called! So we just do the joint
3207  // movement code here.
3208 
3209  if (actor.SOPName != null &&
3210  joints_connecting_actor.ContainsKey(actor.SOPName) &&
3211  joints_connecting_actor[actor.SOPName] != null &&
3212  joints_connecting_actor[actor.SOPName].Count > 0)
3213  {
3214  foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3215  {
3216  if (affectedJoint.IsInPhysicsEngine)
3217  {
3218  DoJointMoved(affectedJoint);
3219  }
3220  else
3221  {
3222  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);
3223  }
3224  }
3225  }
3226  }
3227 
3228  public override void GetResults()
3229  {
3230  }
3231 
3232  public override bool IsThreaded
3233  {
3234  // for now we won't be multithreaded
3235  get { return false; }
3236  }
3237 
3238  public override void SetTerrain(float[] heightMap)
3239  {
3240  if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3241  {
3242  if (m_parentScene is OdeScene)
3243  {
3244  ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3245  }
3246  }
3247  else
3248  {
3249  SetTerrain(heightMap, m_worldOffset);
3250  }
3251  }
3252 
3253  private void SetTerrain(float[] heightMap, Vector3 pOffset)
3254  {
3255  int startTime = Util.EnvironmentTickCount();
3256  m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset);
3257 
3258 
3259  float[] _heightmap;
3260 
3261  // ok im lasy this are just a aliases
3262  uint regionsizeX = m_regionWidth;
3263  uint regionsizeY = m_regionHeight;
3264 
3265  // map is rotated
3266  uint heightmapWidth = regionsizeY + 2;
3267  uint heightmapHeight = regionsizeX + 2;
3268 
3269  uint heightmapWidthSamples = heightmapWidth + 1;
3270  uint heightmapHeightSamples = heightmapHeight + 1;
3271 
3272  _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
3273 
3274  const float scale = 1.0f;
3275  const float offset = 0.0f;
3276  const float thickness = 10f;
3277  const int wrap = 0;
3278 
3279 
3280  float hfmin = float.MaxValue;
3281  float hfmax = float.MinValue;
3282  float val;
3283  uint xx;
3284  uint yy;
3285 
3286  uint maxXX = regionsizeX - 1;
3287  uint maxYY = regionsizeY - 1;
3288 
3289  // flipping map adding one margin all around so things don't fall in edges
3290 
3291  uint xt = 0;
3292  xx = 0;
3293 
3294 
3295  for (uint x = 0; x < heightmapWidthSamples; x++)
3296  {
3297  if (x > 1 && xx < maxXX)
3298  xx++;
3299  yy = 0;
3300  for (uint y = 0; y < heightmapHeightSamples; y++)
3301  {
3302  if (y > 1 && y < maxYY)
3303  yy += regionsizeX;
3304 
3305  val = heightMap[yy + xx];
3306  if (val < 0.0f)
3307  val = 0.0f;
3308  _heightmap[xt + y] = val;
3309 
3310  if (hfmin > val)
3311  hfmin = val;
3312  if (hfmax < val)
3313  hfmax = val;
3314  }
3315  xt += heightmapHeightSamples;
3316  }
3317 
3318  lock (OdeLock)
3319  {
3320  d.AllocateODEDataForThread(~0U);
3321 
3322  IntPtr GroundGeom = IntPtr.Zero;
3323  if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3324  {
3325  RegionTerrain.Remove(pOffset);
3326  if (GroundGeom != IntPtr.Zero)
3327  {
3328  if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3329  {
3330  TerrainHeightFieldHeights.Remove(GroundGeom);
3331  }
3332  d.SpaceRemove(space, GroundGeom);
3333  d.GeomDestroy(GroundGeom);
3334  }
3335 
3336  }
3337  IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3338  d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3339  heightmapWidth, heightmapHeight,
3340  (int)heightmapWidthSamples,
3341  (int)heightmapHeightSamples,
3342  scale, offset, thickness, wrap);
3343 
3344  d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3345  GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3346  if (GroundGeom != IntPtr.Zero)
3347  {
3348  d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3349  d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3350 
3351  }
3352  geom_name_map[GroundGeom] = "Terrain";
3353 
3354  d.Matrix3 R = new d.Matrix3();
3355 
3356  Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3357  Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3358 
3359  q1 = q1 * q2;
3360  Vector3 v3;
3361  float angle;
3362  q1.GetAxisAngle(out v3, out angle);
3363 
3364  d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3365  d.GeomSetRotation(GroundGeom, ref R);
3366  d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0.0f);
3367  IntPtr testGround = IntPtr.Zero;
3368  if (RegionTerrain.TryGetValue(pOffset, out testGround))
3369  {
3370  RegionTerrain.Remove(pOffset);
3371  }
3372  RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3373  TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3374  }
3375 
3376  m_log.DebugFormat(
3377  "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime));
3378  }
3379 
3380  public override void DeleteTerrain()
3381  {
3382  }
3383 
3384  internal float GetWaterLevel()
3385  {
3386  return waterlevel;
3387  }
3388 
3389  public override bool SupportsCombining()
3390  {
3391  return m_suportCombine;
3392  }
3393 
3394  public override void SetWaterLevel(float baseheight)
3395  {
3396  waterlevel = baseheight;
3397  }
3398 
3399  [HandleProcessCorruptedStateExceptions]
3400  public override void Dispose()
3401  {
3402  lock(SimulationLock)
3403  lock(OdeLock)
3404  {
3405  if(world == IntPtr.Zero)
3406  return;
3407 
3408  _worldInitialized = false;
3409 
3410  d.AllocateODEDataForThread(~0U);
3411 
3412  if (m_rayCastManager != null)
3413  {
3414  m_rayCastManager.Dispose();
3415  m_rayCastManager = null;
3416  }
3417 
3418  lock (_prims)
3419  {
3420  foreach (OdePrim prm in _prims)
3421  {
3422  RemovePrim(prm);
3423  }
3424  }
3425 
3426  //foreach (OdeCharacter act in _characters)
3427  //{
3428  //RemoveAvatar(act);
3429  //}
3430  IntPtr GroundGeom = IntPtr.Zero;
3431  if (RegionTerrain.TryGetValue(m_worldOffset, out GroundGeom))
3432  {
3433  RegionTerrain.Remove(m_worldOffset);
3434  if (GroundGeom != IntPtr.Zero)
3435  {
3436  if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3437  TerrainHeightFieldHeights.Remove(GroundGeom);
3438  d.GeomDestroy(GroundGeom);
3439  }
3440  }
3441 
3442  try
3443  {
3444  d.WorldDestroy(world);
3445  world = IntPtr.Zero;
3446  }
3447  catch (AccessViolationException e)
3448  {
3449  m_log.ErrorFormat("[ODE SCENE]: exception {0}", e.Message);
3450  }
3451  }
3452  }
3453 
3454  public override Dictionary<uint, float> GetTopColliders()
3455  {
3456  Dictionary<uint, float> topColliders;
3457 
3458  lock (_prims)
3459  {
3460  List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
3461  orderedPrims.OrderByDescending(p => p.CollisionScore);
3462  topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
3463 
3464  foreach (OdePrim p in _prims)
3465  p.CollisionScore = 0;
3466  }
3467 
3468  return topColliders;
3469  }
3470 
3471  public override bool SupportsRayCast()
3472  {
3473  return true;
3474  }
3475 
3476  public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3477  {
3478  if (retMethod != null)
3479  {
3480  m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3481  }
3482  }
3483 
3484  public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
3485  {
3486  if (retMethod != null)
3487  {
3488  m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
3489  }
3490  }
3491 
3492  public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
3493  {
3494  ContactResult[] ourResults = null;
3495  RayCallback retMethod = delegate(List<ContactResult> results)
3496  {
3497  ourResults = new ContactResult[results.Count];
3498  results.CopyTo(ourResults, 0);
3499  };
3500  int waitTime = 0;
3501  m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
3502  while (ourResults == null && waitTime < 1000)
3503  {
3504  Thread.Sleep(1);
3505  waitTime++;
3506  }
3507  if (ourResults == null)
3508  return new List<ContactResult> ();
3509  return new List<ContactResult>(ourResults);
3510  }
3511 
3512  public override Dictionary<string, float> GetStats()
3513  {
3514  if (!CollectStats)
3515  return null;
3516 
3517  Dictionary<string, float> returnStats;
3518 
3519  lock (OdeLock)
3520  {
3521  returnStats = new Dictionary<string, float>(m_stats);
3522 
3523  // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by
3524  // 3 from the SimStatsReporter.
3525  returnStats[ODETotalAvatarsStatName] = _characters.Count * 3;
3526  returnStats[ODETotalPrimsStatName] = _prims.Count * 3;
3527  returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3;
3528 
3529  InitializeExtraStats();
3530  }
3531 
3532  returnStats[ODEOtherCollisionFrameMsStatName]
3533  = returnStats[ODEOtherCollisionFrameMsStatName]
3534  - returnStats[ODENativeSpaceCollisionFrameMsStatName]
3535  - returnStats[ODENativeGeomCollisionFrameMsStatName];
3536 
3537  return returnStats;
3538  }
3539 
3540  private void InitializeExtraStats()
3541  {
3542  m_stats[ODETotalFrameMsStatName] = 0;
3543  m_stats[ODEAvatarTaintMsStatName] = 0;
3544  m_stats[ODEPrimTaintMsStatName] = 0;
3545  m_stats[ODEAvatarForcesFrameMsStatName] = 0;
3546  m_stats[ODEPrimForcesFrameMsStatName] = 0;
3547  m_stats[ODERaycastingFrameMsStatName] = 0;
3548  m_stats[ODENativeStepFrameMsStatName] = 0;
3549  m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
3550  m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
3551  m_stats[ODEOtherCollisionFrameMsStatName] = 0;
3552  m_stats[ODECollisionNotificationFrameMsStatName] = 0;
3553  m_stats[ODEAvatarContactsStatsName] = 0;
3554  m_stats[ODEPrimContactsStatName] = 0;
3555  m_stats[ODEAvatarUpdateFrameMsStatName] = 0;
3556  m_stats[ODEPrimUpdateFrameMsStatName] = 0;
3557  }
3558  }
3559 }
override bool IsPhysical
Is this prim subject to physics? Even if not, it's still solid for collision purposes.
Definition: ODEPrim.cs:80
override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position, Quaternion rotation, string parms, List< string > bodyNames, string trackedBodyName, Quaternion localRotation)
Add a request for joint creation.
Definition: OdeScene.cs:2074
uint RegionSizeX
X dimension of the region.
Definition: RegionInfo.cs:161
override List< ContactResult > RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
Definition: OdeScene.cs:3492
override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
Definition: OdeScene.cs:1830
uint RegionSizeY
X dimension of the region.
Definition: RegionInfo.cs:169
override Vector3 GetJointAxis(PhysicsJoint joint)
Get joint axis.
Definition: OdeScene.cs:2169
delegate void RayCallback(List< ContactResult > list)
override bool SupportsRayCast()
True if the physics plugin supports raycasting against the physics scene
Definition: OdeScene.cs:3471
override float Simulate(float timeStep)
This is our main simulate loop
Definition: OdeScene.cs:2693
RegionSettings RegionSettings
Definition: RegionInfo.cs:290
override void RequestJointDeletion(string ObjectNameInScene)
Definition: OdeScene.cs:1913
override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
Add an avatar
Definition: OdeScene.cs:1725
override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
Definition: OdeScene.cs:1629
delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal)
override void AddPhysicsActorTaint(PhysicsActor actor)
Called after our prim properties are set Scale, position etc.
Definition: OdeScene.cs:2619
Processes raycast requests as ODE is in a state to be able to do them. This ensures that it's thread ...
Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ours...
Definition: ODEPrim.cs:59
override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
Queue a raycast against the physics scene. The provided callback method will be called when the rayca...
Definition: OdeScene.cs:3476
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
string SOPName
This is being used by ODE joint code.
override Vector3 GetJointAnchor(PhysicsJoint joint)
Definition: OdeScene.cs:2133
override Dictionary< uint, float > GetTopColliders()
Definition: OdeScene.cs:3454
override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
Definition: OdeScene.cs:3484
OdeScene(Scene pscene, IConfigSource psourceconfig, string pname)
Definition: OdeScene.cs:503
override void SetWaterLevel(float baseheight)
Definition: OdeScene.cs:3394
override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
Definition: OdeScene.cs:2122
IntPtr prim_geom
The prim geometry, used for collision detection.
Definition: ODEPrim.cs:186
override void SetTerrain(float[] heightMap)
Definition: OdeScene.cs:3238
Material
Material type for a primitive
Definition: OdeScene.cs:79
uint RegionSizeZ
Z dimension of the region.
Definition: RegionInfo.cs:177
override void RemoveAvatar(PhysicsActor actor)
Remove an avatar.
Definition: OdeScene.cs:1742
override void RemovePrim(PhysicsActor prim)
Remove a prim.
Definition: OdeScene.cs:2203
override Dictionary< string, float > GetStats()
Get statistics about this scene.
Definition: OdeScene.cs:3512