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 // Revision 2011/12/13 by Ubit Umarov
29 //#define SPAM
30 
31 using System;
32 using System.Collections.Generic;
33 using System.Reflection;
34 using System.Runtime.InteropServices;
35 using System.Threading;
36 using System.IO;
37 using System.Diagnostics;
38 using log4net;
39 using Nini.Config;
40 using Mono.Addins;
41 using OdeAPI;
42 using OpenSim.Framework;
43 using OpenSim.Region.Framework.Scenes;
44 using OpenSim.Region.Framework.Interfaces;
45 using OpenSim.Region.PhysicsModules.SharedBase;
46 using OpenMetaverse;
47 
48 namespace OpenSim.Region.PhysicsModule.ubOde
49 {
50  // colision flags of things others can colide with
51  // rays, sensors, probes removed since can't be colided with
52  // The top space where things are placed provided further selection
53  // ie physical are in active space nonphysical in static
54  // this should be exclusive as possible
55 
56  [Flags]
57  public enum CollisionCategories : uint
58  {
59  Disabled = 0,
60  //by 'things' types
61  Space = 0x01,
62  Geom = 0x02, // aka prim/part
63  Character = 0x04,
64  Land = 0x08,
65  Water = 0x010,
66 
67  // by state
68  Phantom = 0x01000,
69  VolumeDtc = 0x02000,
70  Selected = 0x04000,
71  NoShape = 0x08000,
72 
73 
74  All = 0xffffffff
75  }
76 
80  public enum Material : int
81  {
83  Stone = 0,
85  Metal = 1,
87  Glass = 2,
89  Wood = 3,
91  Flesh = 4,
93  Plastic = 5,
95  Rubber = 6,
96 
97  light = 7 // compatibility with old viewers
98  }
99 
100  public enum changes : int
101  {
102  Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?)
103  Remove,
104  Link, // arg AuroraODEPrim new parent prim or null to delink. Makes the prim part of a object with prim parent as root
105  // or removes from a object if arg is null
106  DeLink,
107  Position, // arg Vector3 new position in world coords. Changes prim position. Prim must know if it is root or child
108  Orientation, // arg Quaternion new orientation in world coords. Changes prim position. Prim must know it it is root or child
109  PosOffset, // not in use
110  // arg Vector3 new position in local coords. Changes prim position in object
111  OriOffset, // not in use
112  // arg Vector3 new position in local coords. Changes prim position in object
113  Velocity,
114  AngVelocity,
115  Acceleration,
116  Force,
117  Torque,
118  Momentum,
119 
120  AddForce,
121  AddAngForce,
122  AngLock,
123 
124  Buoyancy,
125 
126  PIDTarget,
127  PIDTau,
128  PIDActive,
129 
131  PIDHoverType,
132  PIDHoverTau,
134 
135  Size,
136  AvatarSize,
137  Shape,
138  PhysRepData,
139  AddPhysRep,
140 
142  VolumeDtc,
143 
144  Physical,
145  Phantom,
146  Selected,
147  disabled,
148  building,
149 
150  VehicleType,
154  VehicleFlags,
155  SetVehicle,
156 
157  Null //keep this last used do dim the methods array. does nothing but pulsing the prim
158  }
159 
160  public struct ODEchangeitem
161  {
164  public changes what;
165  public Object arg;
166  }
167 
168  public class ODEScene : PhysicsScene
169  {
170  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
171 
172  public bool m_OSOdeLib = false;
173  public bool m_suportCombine = false; // mega suport not tested
174  public Scene m_frameWorkScene = null;
175 
176 // private int threadid = 0;
177 
178 // const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce;
179 
180  const d.ContactFlags comumContactFlags = d.ContactFlags.Bounce | d.ContactFlags.Approx1 | d.ContactFlags.Slip1 | d.ContactFlags.Slip2;
181  const float comumContactERP = 0.75f;
182  const float comumContactCFM = 0.0001f;
183  const float comumContactSLIP = 0f;
184 
185  float frictionMovementMult = 0.8f;
186 
187  float TerrainBounce = 0.1f;
188  float TerrainFriction = 0.3f;
189 
190  public float AvatarFriction = 0;// 0.9f * 0.5f;
191 
192  // this netx dimensions are only relevant for terrain partition (mega regions)
193  // WorldExtents below has the simulation dimensions
194  // they should be identical except on mega regions
195  private uint m_regionWidth = Constants.RegionSize;
196  private uint m_regionHeight = Constants.RegionSize;
197 
198  public float ODE_STEPSIZE = 0.020f;
199  public float HalfOdeStep = 0.01f;
200  public int odetimestepMS = 20; // rounded
201  private float metersInSpace = 25.6f;
202  private float m_timeDilation = 1.0f;
203 
204  private DateTime m_lastframe;
205  private DateTime m_lastMeshExpire;
206 
207  public float gravityx = 0f;
208  public float gravityy = 0f;
209  public float gravityz = -9.8f;
210 
211  private float waterlevel = 0f;
212  private int framecount = 0;
213 
214  private float avDensity = 80f;
215  private float avMovementDivisorWalk = 1.3f;
216  private float avMovementDivisorRun = 0.8f;
217  private float minimumGroundFlightOffset = 3f;
218  public float maximumMassObject = 10000.01f;
219  public float geomDefaultDensity = 10.0f;
220 
221  public float maximumAngularVelocity = 12.0f; // default 12rad/s
222  public float maxAngVelocitySQ = 144f; // squared value
223 
224  public float bodyPIDD = 35f;
225  public float bodyPIDG = 25;
226 
227  public int bodyFramesAutoDisable = 5;
228 
229  private d.NearCallback nearCallback;
230 
231  private HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
232  private HashSet<OdePrim> _prims = new HashSet<OdePrim>();
233  private HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
234  private HashSet<OdePrim> _activegroups = new HashSet<OdePrim>();
235 
236  public OpenSim.Framework.LocklessQueue<ODEchangeitem> ChangesQueue = new OpenSim.Framework.LocklessQueue<ODEchangeitem>();
237 
241  private List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
242  private List<PhysicsActor> _collisionEventPrimRemove = new List<PhysicsActor>();
243 
244  private HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
245  public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
246 
247  private float contactsurfacelayer = 0.002f;
248 
249  private int contactsPerCollision = 80;
250  internal IntPtr ContactgeomsArray = IntPtr.Zero;
251  private IntPtr GlobalContactsArray = IntPtr.Zero;
252  private d.Contact SharedTmpcontact = new d.Contact();
253 
254  const int maxContactsbeforedeath = 6000;
255  private volatile int m_global_contactcount = 0;
256 
257  private IntPtr contactgroup;
258 
259  public ContactData[] m_materialContactsData = new ContactData[8];
260 
261  private Dictionary<Vector3, IntPtr> RegionTerrain = new Dictionary<Vector3, IntPtr>();
262  private Dictionary<IntPtr, float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
263  private Dictionary<IntPtr, GCHandle> TerrainHeightFieldHeightsHandlers = new Dictionary<IntPtr, GCHandle>();
264 
265  private int m_physicsiterations = 15;
266  private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
267 // private PhysicsActor PANull = new NullPhysicsActor();
268  private float step_time = 0.0f;
269 
270  public IntPtr world;
271 
272  // split the spaces acording to contents type
273  // ActiveSpace contains characters and active prims
274  // StaticSpace contains land and other that is mostly static in enviroment
275  // this can contain subspaces, like the grid in staticspace
276  // as now space only contains this 2 top spaces
277 
278  public IntPtr TopSpace; // the global space
279  public IntPtr ActiveSpace; // space for active prims
280  public IntPtr CharsSpace; // space for active prims
281  public IntPtr StaticSpace; // space for the static things around
282  public IntPtr GroundSpace; // space for ground
283 
284  // some speedup variables
285  private int spaceGridMaxX;
286  private int spaceGridMaxY;
287  private float spacesPerMeterX;
288  private float spacesPerMeterY;
289 
290  // split static geometry collision into a grid as before
291  private IntPtr[,] staticPrimspace;
292  private IntPtr[] staticPrimspaceOffRegion;
293 
294  public Object OdeLock;
295  public static Object SimulationLock;
296 
297  public IMesher mesher;
298 
299  public IConfigSource m_config;
300 
301  public bool physics_logging = false;
302  public int physics_logging_interval = 0;
303  public bool physics_logging_append_existing_logfile = false;
304 
305  private Vector3 m_worldOffset = Vector3.Zero;
306  public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
307  private PhysicsScene m_parentScene = null;
308 
309  private ODERayCastRequestManager m_rayCastManager;
311 
312  /* maybe needed if ode uses tls
313  private void checkThread()
314  {
315 
316  int th = Thread.CurrentThread.ManagedThreadId;
317  if(th != threadid)
318  {
319  threadid = th;
320  d.AllocateODEDataForThread(~0U);
321  }
322  }
323  */
324 
325  IConfig physicsconfig = null;
326 
327  public ODEScene(Scene pscene, IConfigSource psourceconfig, string pname, bool pOSOdeLib)
328  {
329  OdeLock = new Object();
330 
331  EngineType = pname;
332  PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName;
333 
334  m_config = psourceconfig;
335  m_OSOdeLib = pOSOdeLib;
336 
337 // m_OSOdeLib = false; //debug
338 
339  m_frameWorkScene = pscene;
340 
341  m_frameWorkScene.RegisterModuleInterface<PhysicsScene>(this);
342 
343  Initialization();
344 
345  base.Initialise(m_frameWorkScene.PhysicsRequestAsset,
346  (m_frameWorkScene.Heightmap != null ? m_frameWorkScene.Heightmap.GetFloatsSerialised() : new float[m_frameWorkScene.RegionInfo.RegionSizeX * m_frameWorkScene.RegionInfo.RegionSizeY]),
347  (float)m_frameWorkScene.RegionInfo.RegionSettings.WaterHeight);
348  }
349 
350  public void RegionLoaded()
351  {
352  mesher = m_frameWorkScene.RequestModuleInterface<IMesher>();
353  if (mesher == null)
354  {
355  m_log.ErrorFormat("[ubOde] No mesher. module disabled");
356  return;
357  }
358 
359  m_meshWorker = new ODEMeshWorker(this, m_log, mesher, physicsconfig);
360  m_frameWorkScene.PhysicsEnabled = true;
361  }
367  private void Initialization()
368  {
369  d.AllocateODEDataForThread(~0U);
370 
371  SimulationLock = new Object();
372 
373  nearCallback = near;
374 
375  m_rayCastManager = new ODERayCastRequestManager(this);
376 
377  WorldExtents.X = m_frameWorkScene.RegionInfo.RegionSizeX;
378  m_regionWidth = (uint)WorldExtents.X;
379  WorldExtents.Y = m_frameWorkScene.RegionInfo.RegionSizeY;
380  m_regionHeight = (uint)WorldExtents.Y;
381 
382  m_suportCombine = false;
383 
384  lock (OdeLock)
385  {
386  // Create the world and the first space
387  try
388  {
389  world = d.WorldCreate();
390  TopSpace = d.HashSpaceCreate(IntPtr.Zero);
391 
392  // now the major subspaces
393  ActiveSpace = d.HashSpaceCreate(TopSpace);
394  CharsSpace = d.HashSpaceCreate(TopSpace);
395  StaticSpace = d.HashSpaceCreate(TopSpace);
396  GroundSpace = d.HashSpaceCreate(TopSpace);
397  }
398  catch
399  {
400  // i must RtC#FM
401  // i did!
402  }
403 
404  d.HashSpaceSetLevels(TopSpace, -5, 12);
405  d.HashSpaceSetLevels(ActiveSpace, -5, 10);
406  d.HashSpaceSetLevels(CharsSpace, -4, 3);
407  d.HashSpaceSetLevels(StaticSpace, -5, 12);
408  d.HashSpaceSetLevels(GroundSpace, 0, 8);
409 
410  // demote to second level
411  d.SpaceSetSublevel(ActiveSpace, 1);
412  d.SpaceSetSublevel(CharsSpace, 1);
413  d.SpaceSetSublevel(StaticSpace, 1);
414  d.SpaceSetSublevel(GroundSpace, 1);
415 
416  d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space |
417  CollisionCategories.Geom |
418  CollisionCategories.Character |
419  CollisionCategories.Phantom |
420  CollisionCategories.VolumeDtc
421  ));
422  d.GeomSetCollideBits(ActiveSpace, (uint)(CollisionCategories.Space |
423  CollisionCategories.Geom |
424  CollisionCategories.Character |
425  CollisionCategories.Phantom |
426  CollisionCategories.VolumeDtc
427  ));
428  d.GeomSetCategoryBits(CharsSpace, (uint)(CollisionCategories.Space |
429  CollisionCategories.Geom |
430  CollisionCategories.Character |
431  CollisionCategories.Phantom |
432  CollisionCategories.VolumeDtc
433  ));
434  d.GeomSetCollideBits(CharsSpace, 0);
435 
436  d.GeomSetCategoryBits(StaticSpace, (uint)(CollisionCategories.Space |
437  CollisionCategories.Geom |
438  // CollisionCategories.Land |
439  // CollisionCategories.Water |
440  CollisionCategories.Phantom |
441  CollisionCategories.VolumeDtc
442  ));
443  d.GeomSetCollideBits(StaticSpace, 0);
444 
445  d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land));
446  d.GeomSetCollideBits(GroundSpace, 0);
447 
448  contactgroup = d.JointGroupCreate(maxContactsbeforedeath + 1);
449  //contactgroup
450 
451  d.WorldSetAutoDisableFlag(world, false);
452  }
453 
454 
455  // checkThread();
456 
457 
458  // Defaults
459 
460  int contactsPerCollision = 80;
461 
462  physicsconfig = null;
463 
464  if (m_config != null)
465  {
466  physicsconfig = m_config.Configs["ODEPhysicsSettings"];
467  if (physicsconfig != null)
468  {
469  gravityx = physicsconfig.GetFloat("world_gravityx", gravityx);
470  gravityy = physicsconfig.GetFloat("world_gravityy", gravityy);
471  gravityz = physicsconfig.GetFloat("world_gravityz", gravityz);
472 
473  metersInSpace = physicsconfig.GetFloat("meters_in_small_space", metersInSpace);
474 
475  // contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", contactsurfacelayer);
476 
477  ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
478 
479  avDensity = physicsconfig.GetFloat("av_density", avDensity);
480  avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", avMovementDivisorWalk);
481  avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", avMovementDivisorRun);
482 
483  contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", contactsPerCollision);
484 
485  geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity);
486  bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable);
487 
488  physics_logging = physicsconfig.GetBoolean("physics_logging", false);
489  physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
490  physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
491 
492  minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", minimumGroundFlightOffset);
493  maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", maximumMassObject);
494 
495  avDensity *= 3f / 80f; // scale other engines density option to this
496  }
497  }
498 
499  float heartbeat = 1/m_frameWorkScene.FrameTime;
500  maximumAngularVelocity = 0.49f * heartbeat *(float)Math.PI;
501  maxAngVelocitySQ = maximumAngularVelocity * maximumAngularVelocity;
502 
503  d.WorldSetCFM(world, comumContactCFM);
504  d.WorldSetERP(world, comumContactERP);
505 
506  d.WorldSetGravity(world, gravityx, gravityy, gravityz);
507 
508  d.WorldSetLinearDamping(world, 0.002f);
509  d.WorldSetAngularDamping(world, 0.002f);
510  d.WorldSetAngularDampingThreshold(world, 0f);
511  d.WorldSetLinearDampingThreshold(world, 0f);
512  d.WorldSetMaxAngularSpeed(world, maximumAngularVelocity);
513 
514  d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
515 
516  d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
517  d.WorldSetContactMaxCorrectingVel(world, 60.0f);
518 
519  HalfOdeStep = ODE_STEPSIZE * 0.5f;
520  odetimestepMS = (int)(1000.0f * ODE_STEPSIZE + 0.5f);
521 
522  ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf);
523  GlobalContactsArray = Marshal.AllocHGlobal((maxContactsbeforedeath + 100) * d.Contact.unmanagedSizeOf);
524 
525  SharedTmpcontact.geom.g1 = IntPtr.Zero;
526  SharedTmpcontact.geom.g2 = IntPtr.Zero;
527 
528  SharedTmpcontact.geom.side1 = -1;
529  SharedTmpcontact.geom.side2 = -1;
530 
531  SharedTmpcontact.surface.mode = comumContactFlags;
532  SharedTmpcontact.surface.mu = 0;
533  SharedTmpcontact.surface.bounce = 0;
534  SharedTmpcontact.surface.soft_cfm = comumContactCFM;
535  SharedTmpcontact.surface.soft_erp = comumContactERP;
536  SharedTmpcontact.surface.slip1 = comumContactSLIP;
537  SharedTmpcontact.surface.slip2 = comumContactSLIP;
538 
539  m_materialContactsData[(int)Material.Stone].mu = 0.8f;
540  m_materialContactsData[(int)Material.Stone].bounce = 0.4f;
541 
542  m_materialContactsData[(int)Material.Metal].mu = 0.3f;
543  m_materialContactsData[(int)Material.Metal].bounce = 0.4f;
544 
545  m_materialContactsData[(int)Material.Glass].mu = 0.2f;
546  m_materialContactsData[(int)Material.Glass].bounce = 0.7f;
547 
548  m_materialContactsData[(int)Material.Wood].mu = 0.6f;
549  m_materialContactsData[(int)Material.Wood].bounce = 0.5f;
550 
551  m_materialContactsData[(int)Material.Flesh].mu = 0.9f;
552  m_materialContactsData[(int)Material.Flesh].bounce = 0.3f;
553 
554  m_materialContactsData[(int)Material.Plastic].mu = 0.4f;
555  m_materialContactsData[(int)Material.Plastic].bounce = 0.7f;
556 
557  m_materialContactsData[(int)Material.Rubber].mu = 0.9f;
558  m_materialContactsData[(int)Material.Rubber].bounce = 0.95f;
559 
560  m_materialContactsData[(int)Material.light].mu = 0.0f;
561  m_materialContactsData[(int)Material.light].bounce = 0.0f;
562 
563 
564  spacesPerMeterX = 1.0f / metersInSpace;
565  spacesPerMeterY = spacesPerMeterX;
566  spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX);
567  spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY);
568 
569  if (spaceGridMaxX > 24)
570  {
571  spaceGridMaxX = 24;
572  spacesPerMeterX = spaceGridMaxX / WorldExtents.X;
573  }
574 
575  if (spaceGridMaxY > 24)
576  {
577  spaceGridMaxY = 24;
578  spacesPerMeterY = spaceGridMaxY / WorldExtents.Y;
579  }
580 
581  staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY];
582 
583  // create all spaces now
584  int i, j;
585  IntPtr newspace;
586 
587  for (i = 0; i < spaceGridMaxX; i++)
588  for (j = 0; j < spaceGridMaxY; j++)
589  {
590  newspace = d.HashSpaceCreate(StaticSpace);
591  d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space);
592  waitForSpaceUnlock(newspace);
593  d.SpaceSetSublevel(newspace, 2);
594  d.HashSpaceSetLevels(newspace, -2, 8);
595  d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space |
596  CollisionCategories.Geom |
597  CollisionCategories.Land |
598  CollisionCategories.Water |
599  CollisionCategories.Phantom |
600  CollisionCategories.VolumeDtc
601  ));
602  d.GeomSetCollideBits(newspace, 0);
603 
604  staticPrimspace[i, j] = newspace;
605  }
606 
607  // let this now be index limit
608  spaceGridMaxX--;
609  spaceGridMaxY--;
610 
611  // create 4 off world spaces (x<0,x>max,y<0,y>max)
612  staticPrimspaceOffRegion = new IntPtr[4];
613 
614  for (i = 0; i < 4; i++)
615  {
616  newspace = d.HashSpaceCreate(StaticSpace);
617  d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space);
618  waitForSpaceUnlock(newspace);
619  d.SpaceSetSublevel(newspace, 2);
620  d.HashSpaceSetLevels(newspace, -2, 8);
621  d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space |
622  CollisionCategories.Geom |
623  CollisionCategories.Land |
624  CollisionCategories.Water |
625  CollisionCategories.Phantom |
626  CollisionCategories.VolumeDtc
627  ));
628  d.GeomSetCollideBits(newspace, 0);
629 
630  staticPrimspaceOffRegion[i] = newspace;
631  }
632 
633  m_lastframe = DateTime.UtcNow;
634  m_lastMeshExpire = m_lastframe;
635  }
636 
637  internal void waitForSpaceUnlock(IntPtr space)
638  {
639  //if (space != IntPtr.Zero)
640  //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
641  }
642 
643  #region Collision Detection
644 
645  // sets a global contact for a joint for contactgeom , and base contact description)
646  private IntPtr CreateContacJoint(ref d.ContactGeom contactGeom,bool smooth)
647  {
648  if (m_global_contactcount >= maxContactsbeforedeath)
649  return IntPtr.Zero;
650 
651  m_global_contactcount++;
652  if(smooth)
653  SharedTmpcontact.geom.depth = contactGeom.depth * 0.05f;
654  else
655  SharedTmpcontact.geom.depth = contactGeom.depth;
656  SharedTmpcontact.geom.pos = contactGeom.pos;
657  SharedTmpcontact.geom.normal = contactGeom.normal;
658 
659  IntPtr contact = new IntPtr(GlobalContactsArray.ToInt64() + (Int64)(m_global_contactcount * d.Contact.unmanagedSizeOf));
660  Marshal.StructureToPtr(SharedTmpcontact, contact, true);
661  return d.JointCreateContactPtr(world, contactgroup, contact);
662  }
663 
664  private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
665  {
666  if (ContactgeomsArray == IntPtr.Zero || index >= contactsPerCollision)
667  return false;
668 
669  IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
670  newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
671  return true;
672  }
673 
681 
682  private void near(IntPtr space, IntPtr g1, IntPtr g2)
683  {
684  // no lock here! It's invoked from within Simulate(), which is thread-locked
685 
686  if (m_global_contactcount >= maxContactsbeforedeath)
687  return;
688 
689  // Test if we're colliding a geom with a space.
690  // If so we have to drill down into the space recursively
691 
692  if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
693  return;
694 
695  if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
696  {
697  // We'll be calling near recursivly if one
698  // of them is a space to find all of the
699  // contact points in the space
700  try
701  {
702  d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
703  }
704  catch (AccessViolationException)
705  {
706  m_log.Warn("[PHYSICS]: Unable to collide test a space");
707  return;
708  }
709  //here one should check collisions of geoms inside a space
710  // but on each space we only should have geoms that not colide amoung each other
711  // so we don't dig inside spaces
712  return;
713  }
714 
715  // get geom bodies to check if we already a joint contact
716  // guess this shouldn't happen now
717  IntPtr b1 = d.GeomGetBody(g1);
718  IntPtr b2 = d.GeomGetBody(g2);
719 
720  // d.GeomClassID id = d.GeomGetClass(g1);
721 
722  // Figure out how many contact points we have
723  int count = 0;
724  try
725  {
726  // Colliding Geom To Geom
727  // This portion of the function 'was' blatantly ripped off from BoxStack.cs
728 
729  if (g1 == g2)
730  return; // Can't collide with yourself
731 
732  if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
733  return;
734  /*
735  // debug
736  PhysicsActor dp2;
737  if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
738  {
739  d.AABB aabb;
740  d.GeomGetAABB(g2, out aabb);
741  float x = aabb.MaxX - aabb.MinX;
742  float y = aabb.MaxY - aabb.MinY;
743  float z = aabb.MaxZ - aabb.MinZ;
744  if (x > 60.0f || y > 60.0f || z > 60.0f)
745  {
746  if (!actor_name_map.TryGetValue(g2, out dp2))
747  m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
748  else
749  m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})",
750  dp2.Name, dp2.Size, x, y, z,
751  dp2.Position.ToString(),
752  dp2.Orientation.ToString(),
753  dp2.Orientation.Length());
754  return;
755  }
756  }
757  //
758  */
759 
760 
761  if (d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc ||
762  d.GeomGetCategoryBits(g2) == (uint)CollisionCategories.VolumeDtc)
763  {
764  int cflags;
765  unchecked
766  {
767  cflags = (int)(1 | d.CONTACTS_UNIMPORTANT);
768  }
769  count = d.CollidePtr(g1, g2, cflags, ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
770  }
771  else
772  count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
773  }
774  catch (SEHException)
775  {
776  m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
777  // ode.drelease(world);
778  base.TriggerPhysicsBasedRestart();
779  }
780  catch (Exception e)
781  {
782  m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
783  return;
784  }
785 
786  // contacts done
787  if (count == 0)
788  return;
789 
790  // try get physical actors
791  PhysicsActor p1;
792  PhysicsActor p2;
793 
794  if (!actor_name_map.TryGetValue(g1, out p1))
795  {
796  m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 1");
797  return;
798  }
799 
800  if (!actor_name_map.TryGetValue(g2, out p2))
801  {
802  m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
803  return;
804  }
805 
806  // update actors collision score
807  if (p1.CollisionScore >= float.MaxValue - count)
808  p1.CollisionScore = 0;
809  p1.CollisionScore += count;
810 
811  if (p2.CollisionScore >= float.MaxValue - count)
812  p2.CollisionScore = 0;
813  p2.CollisionScore += count;
814 
815  // get first contact
816  d.ContactGeom curContact = new d.ContactGeom();
817 
818  if (!GetCurContactGeom(0, ref curContact))
819  return;
820 
821  ContactPoint maxDepthContact = new ContactPoint();
822 
823  // do volume detection case
824  if ((p1.IsVolumeDtc || p2.IsVolumeDtc))
825  {
826  maxDepthContact = new ContactPoint(
827  new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
828  new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
829  curContact.depth, false
830  );
831 
832  collision_accounting_events(p1, p2, maxDepthContact);
833  return;
834  }
835 
836  // big messy collision analises
837 
838  float mu = 0;
839  float bounce = 0;
840 // bool IgnoreNegSides = false;
841 
842  ContactData contactdata1 = new ContactData(0, 0, false);
843  ContactData contactdata2 = new ContactData(0, 0, false);
844 
845  bool dop1ava = false;
846  bool dop2ava = false;
847  bool ignore = false;
848  bool smoothMesh = false;
849 
850  switch (p1.PhysicsActorType)
851  {
852  case (int)ActorTypes.Agent:
853  {
854  dop1ava = true;
855  switch (p2.PhysicsActorType)
856  {
857  case (int)ActorTypes.Agent:
858  case (int)ActorTypes.Prim:
859  break;
860 
861  default:
862  ignore = true; // avatar to terrain and water ignored
863  break;
864  }
865  break;
866  }
867 
868  case (int)ActorTypes.Prim:
869  {
870  switch (p2.PhysicsActorType)
871  {
872  case (int)ActorTypes.Agent:
873  dop2ava = true;
874  break;
875 
876  case (int)ActorTypes.Prim:
877  Vector3 relV = p1.Velocity - p2.Velocity;
878  float relVlenSQ = relV.LengthSquared();
879  if (relVlenSQ > 0.0001f)
880  {
881  p1.CollidingObj = true;
882  p2.CollidingObj = true;
883  }
884  p1.getContactData(ref contactdata1);
885  p2.getContactData(ref contactdata2);
886  bounce = contactdata1.bounce * contactdata2.bounce;
887  mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);
888 
889  if (relVlenSQ > 0.01f)
890  mu *= frictionMovementMult;
891 
892  if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass &&
893  d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
894  smoothMesh = true;
895  break;
896 
897  case (int)ActorTypes.Ground:
898  p1.getContactData(ref contactdata1);
899  bounce = contactdata1.bounce * TerrainBounce;
900  mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction);
901 
902  if (Math.Abs(p1.Velocity.X) > 0.1f || Math.Abs(p1.Velocity.Y) > 0.1f)
903  mu *= frictionMovementMult;
904  p1.CollidingGround = true;
905 
906  if(d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
907  smoothMesh = true;
908  break;
909 
910  case (int)ActorTypes.Water:
911  default:
912  ignore = true;
913  break;
914  }
915  }
916  break;
917 
918  case (int)ActorTypes.Ground:
919  if (p2.PhysicsActorType == (int)ActorTypes.Prim)
920  {
921  p2.CollidingGround = true;
922  p2.getContactData(ref contactdata2);
923  bounce = contactdata2.bounce * TerrainBounce;
924  mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction);
925 
926 // if (curContact.side1 > 0) // should be 2 ?
927 // IgnoreNegSides = true;
928 
929  if (Math.Abs(p2.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y) > 0.1f)
930  mu *= frictionMovementMult;
931 
932  if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass)
933  smoothMesh = true;
934  }
935  else
936  ignore = true;
937  break;
938 
939  case (int)ActorTypes.Water:
940  default:
941  break;
942  }
943 
944  if (ignore)
945  return;
946 
947  IntPtr Joint;
948  bool FeetCollision = false;
949  int ncontacts = 0;
950 
951  int i = 0;
952 
953  maxDepthContact = new ContactPoint();
954  maxDepthContact.PenetrationDepth = float.MinValue;
955  ContactPoint minDepthContact = new ContactPoint();
956  minDepthContact.PenetrationDepth = float.MaxValue;
957 
958  SharedTmpcontact.geom.depth = 0;
959  SharedTmpcontact.surface.mu = mu;
960  SharedTmpcontact.surface.bounce = bounce;
961 
962  d.ContactGeom altContact = new d.ContactGeom();
963  bool useAltcontact = false;
964  bool noskip = true;
965 
966  if(dop1ava || dop2ava)
967  smoothMesh = false;
968 
969  while (true)
970  {
971  noskip = true;
972  useAltcontact = false;
973 
974  if (dop1ava)
975  {
976  if ((((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
977  {
978  if (p2.PhysicsActorType == (int)ActorTypes.Agent)
979  {
980  p1.CollidingObj = true;
981  p2.CollidingObj = true;
982  }
983  else if (p2.Velocity.LengthSquared() > 0.0f)
984  p2.CollidingObj = true;
985  }
986  else
987  noskip = false;
988  }
989  else if (dop2ava)
990  {
991  if ((((OdeCharacter)p2).Collide(g2, g1, true, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
992  {
993  if (p1.PhysicsActorType == (int)ActorTypes.Agent)
994  {
995  p1.CollidingObj = true;
996  p2.CollidingObj = true;
997  }
998  else if (p2.Velocity.LengthSquared() > 0.0f)
999  p1.CollidingObj = true;
1000  }
1001  else
1002  noskip = false;
1003  }
1004 
1005  if (noskip)
1006  {
1007  if(useAltcontact)
1008  Joint = CreateContacJoint(ref altContact,smoothMesh);
1009  else
1010  Joint = CreateContacJoint(ref curContact,smoothMesh);
1011 
1012  if (Joint == IntPtr.Zero)
1013  break;
1014 
1015  d.JointAttach(Joint, b1, b2);
1016 
1017  ncontacts++;
1018 
1019  if (curContact.depth > maxDepthContact.PenetrationDepth)
1020  {
1021  maxDepthContact.Position.X = curContact.pos.X;
1022  maxDepthContact.Position.Y = curContact.pos.Y;
1023  maxDepthContact.Position.Z = curContact.pos.Z;
1024  maxDepthContact.PenetrationDepth = curContact.depth;
1025  maxDepthContact.CharacterFeet = FeetCollision;
1026  }
1027 
1028  if (curContact.depth < minDepthContact.PenetrationDepth)
1029  {
1030  minDepthContact.PenetrationDepth = curContact.depth;
1031  minDepthContact.SurfaceNormal.X = curContact.normal.X;
1032  minDepthContact.SurfaceNormal.Y = curContact.normal.Y;
1033  minDepthContact.SurfaceNormal.Z = curContact.normal.Z;
1034  }
1035  }
1036 
1037  if (++i >= count)
1038  break;
1039 
1040  if (!GetCurContactGeom(i, ref curContact))
1041  break;
1042  }
1043 
1044  if (ncontacts > 0)
1045  {
1046  maxDepthContact.SurfaceNormal.X = minDepthContact.SurfaceNormal.X;
1047  maxDepthContact.SurfaceNormal.Y = minDepthContact.SurfaceNormal.Y;
1048  maxDepthContact.SurfaceNormal.Z = minDepthContact.SurfaceNormal.Z;
1049 
1050  collision_accounting_events(p1, p2, maxDepthContact);
1051  }
1052  }
1053 
1054  private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1055  {
1056  uint obj2LocalID = 0;
1057 
1058  bool p1events = p1.SubscribedEvents();
1059  bool p2events = p2.SubscribedEvents();
1060 
1061  if (p1.IsVolumeDtc)
1062  p2events = false;
1063  if (p2.IsVolumeDtc)
1064  p1events = false;
1065 
1066  if (!p2events && !p1events)
1067  return;
1068 
1069  Vector3 vel = Vector3.Zero;
1070  if (p2 != null && p2.IsPhysical)
1071  vel = p2.Velocity;
1072 
1073  if (p1 != null && p1.IsPhysical)
1074  vel -= p1.Velocity;
1075 
1076  contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal);
1077 
1078  switch ((ActorTypes)p1.PhysicsActorType)
1079  {
1080  case ActorTypes.Agent:
1081  case ActorTypes.Prim:
1082  {
1083  switch ((ActorTypes)p2.PhysicsActorType)
1084  {
1085  case ActorTypes.Agent:
1086  case ActorTypes.Prim:
1087  if (p2events)
1088  {
1089  AddCollisionEventReporting(p2);
1090  p2.AddCollisionEvent(p1.ParentActor.LocalID, contact);
1091  }
1092  obj2LocalID = p2.ParentActor.LocalID;
1093  break;
1094 
1095  case ActorTypes.Ground:
1096  case ActorTypes.Unknown:
1097  default:
1098  obj2LocalID = 0;
1099  break;
1100  }
1101  if (p1events)
1102  {
1103  contact.SurfaceNormal = -contact.SurfaceNormal;
1104  AddCollisionEventReporting(p1);
1105  p1.AddCollisionEvent(obj2LocalID, contact);
1106  }
1107  break;
1108  }
1109  case ActorTypes.Ground:
1110  case ActorTypes.Unknown:
1111  default:
1112  {
1113  if (p2events && !p2.IsVolumeDtc)
1114  {
1115  AddCollisionEventReporting(p2);
1116  p2.AddCollisionEvent(0, contact);
1117  }
1118  break;
1119  }
1120  }
1121  }
1122 
1127  private void collision_optimized()
1128  {
1129  lock (_characters)
1130  {
1131  try
1132  {
1133  foreach (OdeCharacter chr in _characters)
1134  {
1135  if (chr == null)
1136  continue;
1137 
1138  chr.IsColliding = false;
1139  // chr.CollidingGround = false; not done here
1140  chr.CollidingObj = false;
1141 
1142  if(chr.Body == IntPtr.Zero || chr.collider == IntPtr.Zero )
1143  continue;
1144 
1145  // do colisions with static space
1146  d.SpaceCollide2(chr.collider, StaticSpace, IntPtr.Zero, nearCallback);
1147 
1148  // no coll with gnd
1149  }
1150  // chars with chars
1151  d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback);
1152 
1153  }
1154  catch (AccessViolationException)
1155  {
1156  m_log.Warn("[PHYSICS]: Unable to collide Character to static space");
1157  }
1158 
1159  }
1160 
1161  lock (_activeprims)
1162  {
1163  foreach (OdePrim aprim in _activeprims)
1164  {
1165  aprim.CollisionScore = 0;
1166  aprim.IsColliding = false;
1167  }
1168  }
1169  lock (_activegroups)
1170  {
1171  try
1172  {
1173  foreach (OdePrim aprim in _activegroups)
1174  {
1175  if(!aprim.m_outbounds && d.BodyIsEnabled(aprim.Body) &&
1176  aprim.collide_geom != IntPtr.Zero)
1177  {
1178  d.SpaceCollide2(StaticSpace, aprim.collide_geom, IntPtr.Zero, nearCallback);
1179  d.SpaceCollide2(GroundSpace, aprim.collide_geom, IntPtr.Zero, nearCallback);
1180  }
1181  }
1182  }
1183  catch (Exception e)
1184  {
1185  m_log.Warn("[PHYSICS]: Unable to collide Active to Static: " + e.Message);
1186  }
1187  }
1188 
1189  // colide active amoung them
1190  try
1191  {
1192  d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback);
1193  }
1194  catch (Exception e)
1195  {
1196  m_log.Warn("[PHYSICS]: Unable to collide in Active: " + e.Message);
1197  }
1198 
1199  // and with chars
1200  try
1201  {
1202  d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback);
1203  }
1204  catch (Exception e)
1205  {
1206  m_log.Warn("[PHYSICS]: Unable to collide Active to Character: " + e.Message);
1207  }
1208  }
1209 
1210  #endregion
1211  public void AddCollisionEventReporting(PhysicsActor obj)
1216  {
1217  if (!_collisionEventPrim.Contains(obj))
1218  _collisionEventPrim.Add(obj);
1219  }
1220 
1226  {
1227  if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj))
1228  _collisionEventPrimRemove.Add(obj);
1229  }
1230 
1231  public override float TimeDilation
1232  {
1233  get { return m_timeDilation; }
1234  }
1235 
1236  public override bool SupportsNINJAJoints
1237  {
1238  get { return false; }
1239  }
1240 
1241  #region Add/Remove Entities
1242 
1243  public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
1244  {
1245  return null;
1246  }
1247 
1248  public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, float feetOffset, bool isFlying)
1249  {
1250  OdeCharacter newAv = new OdeCharacter(localID, avName, this, position,
1251  size, feetOffset, avDensity, avMovementDivisorWalk, avMovementDivisorRun);
1252  newAv.Flying = isFlying;
1253  newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1254 
1255  return newAv;
1256  }
1257 
1258  public void AddCharacter(OdeCharacter chr)
1259  {
1260  lock (_characters)
1261  {
1262  if (!_characters.Contains(chr))
1263  {
1264  _characters.Add(chr);
1265  if (chr.bad)
1266  m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1267  }
1268  }
1269  }
1270 
1272  {
1273  lock (_characters)
1274  {
1275  if (_characters.Contains(chr))
1276  {
1277  _characters.Remove(chr);
1278  }
1279  }
1280  }
1281 
1282  public void BadCharacter(OdeCharacter chr)
1283  {
1284  lock (_badCharacter)
1285  {
1286  if (!_badCharacter.Contains(chr))
1287  _badCharacter.Add(chr);
1288  }
1289  }
1290 
1291  public override void RemoveAvatar(PhysicsActor actor)
1292  {
1293  //m_log.Debug("[PHYSICS]:ODELOCK");
1294  lock (OdeLock)
1295  {
1296  d.AllocateODEDataForThread(0);
1297  ((OdeCharacter) actor).Destroy();
1298  }
1299  }
1300 
1301 
1302  public void addActivePrim(OdePrim activatePrim)
1303  {
1304  // adds active prim..
1305  lock (_activeprims)
1306  {
1307  if (!_activeprims.Contains(activatePrim))
1308  _activeprims.Add(activatePrim);
1309  }
1310  }
1311 
1312  public void addActiveGroups(OdePrim activatePrim)
1313  {
1314  lock (_activegroups)
1315  {
1316  if (!_activegroups.Contains(activatePrim))
1317  _activegroups.Add(activatePrim);
1318  }
1319  }
1320 
1321  private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1322  PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID)
1323  {
1324  OdePrim newPrim;
1325  lock (OdeLock)
1326  {
1327 
1328  newPrim = new OdePrim(name, this, position, size, rotation, pbs, isphysical, isPhantom, shapeType, localID);
1329  lock (_prims)
1330  _prims.Add(newPrim);
1331  }
1332  return newPrim;
1333  }
1334 
1335  public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1336  Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid)
1337  {
1338  return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, 0 , localid);
1339  }
1340 
1341 
1342  public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1343  Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
1344  {
1345  return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid);
1346  }
1347 
1348  public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1349  Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid)
1350  {
1351 
1352  return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid);
1353  }
1354 
1355  public void remActivePrim(OdePrim deactivatePrim)
1356  {
1357  lock (_activeprims)
1358  {
1359  _activeprims.Remove(deactivatePrim);
1360  }
1361  }
1362  public void remActiveGroup(OdePrim deactivatePrim)
1363  {
1364  lock (_activegroups)
1365  {
1366  _activegroups.Remove(deactivatePrim);
1367  }
1368  }
1369 
1370  public override void RemovePrim(PhysicsActor prim)
1371  {
1372  // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
1373  // removed in the next physics simulate pass.
1374  if (prim is OdePrim)
1375  {
1376 // lock (OdeLock)
1377  {
1378 
1379  OdePrim p = (OdePrim)prim;
1380  p.setPrimForRemoval();
1381  }
1382  }
1383  }
1384 
1386  {
1387  //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
1388  lock (prim)
1389  {
1390 // RemoveCollisionEventReporting(prim);
1391  lock (_prims)
1392  _prims.Remove(prim);
1393  }
1394 
1395  }
1396 
1397  public bool havePrim(OdePrim prm)
1398  {
1399  lock (_prims)
1400  return _prims.Contains(prm);
1401  }
1402 
1403  public bool haveActor(PhysicsActor actor)
1404  {
1405  if (actor is OdePrim)
1406  {
1407  lock (_prims)
1408  return _prims.Contains((OdePrim)actor);
1409  }
1410  else if (actor is OdeCharacter)
1411  {
1412  lock (_characters)
1413  return _characters.Contains((OdeCharacter)actor);
1414  }
1415  return false;
1416  }
1417 
1418  #endregion
1419 
1420  #region Space Separation Calculation
1421 
1430  public IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace)
1431  {
1432  // moves a prim into another static sub-space or from another space into a static sub-space
1433 
1434  // Called ODEPrim so
1435  // it's already in locked space.
1436 
1437  if (geom == IntPtr.Zero) // shouldn't happen
1438  return IntPtr.Zero;
1439 
1440  // get the static sub-space for current position
1441  IntPtr newspace = calculateSpaceForGeom(pos);
1442 
1443  if (newspace == currentspace) // if we are there all done
1444  return newspace;
1445 
1446  // else remove it from its current space
1447  if (currentspace != IntPtr.Zero && d.SpaceQuery(currentspace, geom))
1448  {
1449  if (d.GeomIsSpace(currentspace))
1450  {
1451  waitForSpaceUnlock(currentspace);
1452  d.SpaceRemove(currentspace, geom);
1453 
1454  if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
1455  {
1456  d.SpaceDestroy(currentspace);
1457  }
1458  }
1459  else
1460  {
1461  m_log.Info("[Physics]: Invalid or empty Space passed to 'MoveGeomToStaticSpace':" + currentspace +
1462  " Geom:" + geom);
1463  }
1464  }
1465  else // odd currentspace is null or doesn't contain the geom? lets try the geom ideia of current space
1466  {
1467  currentspace = d.GeomGetSpace(geom);
1468  if (currentspace != IntPtr.Zero)
1469  {
1470  if (d.GeomIsSpace(currentspace))
1471  {
1472  waitForSpaceUnlock(currentspace);
1473  d.SpaceRemove(currentspace, geom);
1474 
1475  if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
1476  {
1477  d.SpaceDestroy(currentspace);
1478  }
1479 
1480  }
1481  }
1482  }
1483 
1484  // put the geom in the newspace
1485  waitForSpaceUnlock(newspace);
1486  d.SpaceAdd(newspace, geom);
1487 
1488  // let caller know this newspace
1489  return newspace;
1490  }
1491 
1497  public IntPtr calculateSpaceForGeom(Vector3 pos)
1498  {
1499  int x, y;
1500 
1501  if (pos.X < 0)
1502  return staticPrimspaceOffRegion[0];
1503 
1504  if (pos.Y < 0)
1505  return staticPrimspaceOffRegion[2];
1506 
1507  x = (int)(pos.X * spacesPerMeterX);
1508  if (x > spaceGridMaxX)
1509  return staticPrimspaceOffRegion[1];
1510 
1511  y = (int)(pos.Y * spacesPerMeterY);
1512  if (y > spaceGridMaxY)
1513  return staticPrimspaceOffRegion[3];
1514 
1515  return staticPrimspace[x, y];
1516  }
1517 
1518  #endregion
1519 
1520 
1525 
1526  public void AddChange(PhysicsActor actor, changes what, Object arg)
1527  {
1528  ODEchangeitem item = new ODEchangeitem();
1529  item.actor = actor;
1530  item.what = what;
1531  item.arg = arg;
1532  ChangesQueue.Enqueue(item);
1533  }
1534 
1541  public override void AddPhysicsActorTaint(PhysicsActor prim)
1542  {
1543  }
1544 
1545  // does all pending changes generated during region load process
1546  public override void ProcessPreSimulation()
1547  {
1548  lock (OdeLock)
1549  {
1550  if (world == IntPtr.Zero)
1551  {
1552  ChangesQueue.Clear();
1553  return;
1554  }
1555 
1556  d.AllocateODEDataForThread(~0U);
1557 
1558  ODEchangeitem item;
1559 
1560  int donechanges = 0;
1561  if (ChangesQueue.Count > 0)
1562  {
1563  m_log.InfoFormat("[ubOde] start processing pending actor operations");
1564  int tstart = Util.EnvironmentTickCount();
1565 
1566  while (ChangesQueue.Dequeue(out item))
1567  {
1568  if (item.actor != null)
1569  {
1570  try
1571  {
1572  if (item.actor is OdeCharacter)
1573  ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
1574  else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
1575  RemovePrimThreadLocked((OdePrim)item.actor);
1576  }
1577  catch
1578  {
1579  m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}",
1580  item.actor.Name, item.what.ToString());
1581  }
1582  }
1583  donechanges++;
1584  }
1585  int time = Util.EnvironmentTickCountSubtract(tstart);
1586  m_log.InfoFormat("[ubOde] finished {0} operations in {1}ms", donechanges, time);
1587  }
1588  m_log.InfoFormat("[ubOde] {0} prim actors loaded",_prims.Count);
1589  }
1590  }
1591 
1601  public override float Simulate(float reqTimeStep)
1602  {
1603  DateTime now = DateTime.UtcNow;
1604  TimeSpan timedif = now - m_lastframe;
1605  float timeStep = (float)timedif.TotalSeconds;
1606  m_lastframe = now;
1607 
1608  // acumulate time so we can reduce error
1609  step_time += timeStep;
1610 
1611  if (step_time < HalfOdeStep)
1612  return 0;
1613 
1614  if (framecount < 0)
1615  framecount = 0;
1616 
1617  framecount++;
1618 
1619 // checkThread();
1620  int nodeframes = 0;
1621  float fps = 0;
1622 
1623  lock (SimulationLock)
1624  lock(OdeLock)
1625  {
1626  if (world == IntPtr.Zero)
1627  {
1628  ChangesQueue.Clear();
1629  return 0;
1630  }
1631 
1632  ODEchangeitem item;
1633 
1634 // d.WorldSetQuickStepNumIterations(world, curphysiteractions);
1635 
1636  int loopstartMS = Util.EnvironmentTickCount();
1637  int looptimeMS = 0;
1638  int changestimeMS = 0;
1639  int maxChangestime = (int)(reqTimeStep * 500f); // half the time
1640  int maxLoopTime = (int)(reqTimeStep * 1200f); // 1.2 the time
1641 
1642  d.AllocateODEDataForThread(~0U);
1643 
1644  if (ChangesQueue.Count > 0)
1645  {
1646  while (ChangesQueue.Dequeue(out item))
1647  {
1648  if (item.actor != null)
1649  {
1650  try
1651  {
1652  if (item.actor is OdeCharacter)
1653  ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
1654  else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
1655  RemovePrimThreadLocked((OdePrim)item.actor);
1656  }
1657  catch
1658  {
1659  m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}",
1660  item.actor.Name, item.what.ToString());
1661  }
1662  }
1663  changestimeMS = Util.EnvironmentTickCountSubtract(loopstartMS);
1664  if (changestimeMS > maxChangestime)
1665  break;
1666  }
1667  }
1668 
1669  // do simulation taking at most 150ms total time including changes
1670  while (step_time > HalfOdeStep)
1671  {
1672  try
1673  {
1674  // clear pointer/counter to contacts to pass into joints
1675  m_global_contactcount = 0;
1676 
1677 
1678  // Move characters
1679  lock (_characters)
1680  {
1681  List<OdeCharacter> defects = new List<OdeCharacter>();
1682  foreach (OdeCharacter actor in _characters)
1683  {
1684  if (actor != null)
1685  actor.Move(defects);
1686  }
1687  if (defects.Count != 0)
1688  {
1689  foreach (OdeCharacter defect in defects)
1690  {
1691  RemoveCharacter(defect);
1692  }
1693  defects.Clear();
1694  }
1695  }
1696 
1697  // Move other active objects
1698  lock (_activegroups)
1699  {
1700  foreach (OdePrim aprim in _activegroups)
1701  {
1702  aprim.Move();
1703  }
1704  }
1705 
1706  m_rayCastManager.ProcessQueuedRequests();
1707 
1708  collision_optimized();
1709 
1710  foreach (PhysicsActor obj in _collisionEventPrim)
1711  {
1712  if (obj == null)
1713  continue;
1714 
1715  switch ((ActorTypes)obj.PhysicsActorType)
1716  {
1717  case ActorTypes.Agent:
1718  OdeCharacter cobj = (OdeCharacter)obj;
1719  cobj.AddCollisionFrameTime((int)(odetimestepMS));
1720  cobj.SendCollisions();
1721  break;
1722 
1723  case ActorTypes.Prim:
1724  OdePrim pobj = (OdePrim)obj;
1725  if (pobj.Body == IntPtr.Zero || (d.BodyIsEnabled(pobj.Body) && !pobj.m_outbounds))
1726  if (!pobj.m_outbounds)
1727  {
1728  pobj.AddCollisionFrameTime((int)(odetimestepMS));
1729  pobj.SendCollisions();
1730  }
1731  break;
1732  }
1733  }
1734 
1735  foreach (PhysicsActor obj in _collisionEventPrimRemove)
1736  _collisionEventPrim.Remove(obj);
1737 
1738  _collisionEventPrimRemove.Clear();
1739 
1740  // do a ode simulation step
1741  d.WorldQuickStep(world, ODE_STEPSIZE);
1742  d.JointGroupEmpty(contactgroup);
1743 
1744  // update managed ideia of physical data and do updates to core
1745  /*
1746  lock (_characters)
1747  {
1748  foreach (OdeCharacter actor in _characters)
1749  {
1750  if (actor != null)
1751  {
1752  if (actor.bad)
1753  m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
1754 
1755  actor.UpdatePositionAndVelocity();
1756  }
1757  }
1758  }
1759  */
1760 
1761  lock (_activegroups)
1762  {
1763  {
1764  foreach (OdePrim actor in _activegroups)
1765  {
1766  if (actor.IsPhysical)
1767  {
1768  actor.UpdatePositionAndVelocity(framecount);
1769  }
1770  }
1771  }
1772  }
1773  }
1774  catch (Exception e)
1775  {
1776  m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
1777 // ode.dunlock(world);
1778  }
1779 
1780  step_time -= ODE_STEPSIZE;
1781  nodeframes++;
1782 
1783  looptimeMS = Util.EnvironmentTickCountSubtract(loopstartMS);
1784  if (looptimeMS > maxLoopTime)
1785  break;
1786  }
1787 
1788  lock (_badCharacter)
1789  {
1790  if (_badCharacter.Count > 0)
1791  {
1792  foreach (OdeCharacter chr in _badCharacter)
1793  {
1794  RemoveCharacter(chr);
1795  }
1796 
1797  _badCharacter.Clear();
1798  }
1799  }
1800 
1801  timedif = now - m_lastMeshExpire;
1802 
1803  if (timedif.Seconds > 10)
1804  {
1805  mesher.ExpireReleaseMeshs();
1806  m_lastMeshExpire = now;
1807  }
1808 
1809 // information block for in debug breakpoint only
1810 /*
1811  int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
1812  int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
1813  int ngroundgeoms = d.SpaceGetNumGeoms(GroundSpace);
1814 
1815  int nactivegeoms = 0;
1816  int nactivespaces = 0;
1817 
1818  int nstaticgeoms = 0;
1819  int nstaticspaces = 0;
1820  IntPtr sp;
1821 
1822  for (int i = 0; i < ntopactivegeoms; i++)
1823  {
1824  sp = d.SpaceGetGeom(ActiveSpace, i);
1825  if (d.GeomIsSpace(sp))
1826  {
1827  nactivespaces++;
1828  nactivegeoms += d.SpaceGetNumGeoms(sp);
1829  }
1830  else
1831  nactivegeoms++;
1832  }
1833 
1834  for (int i = 0; i < ntopstaticgeoms; i++)
1835  {
1836  sp = d.SpaceGetGeom(StaticSpace, i);
1837  if (d.GeomIsSpace(sp))
1838  {
1839  nstaticspaces++;
1840  nstaticgeoms += d.SpaceGetNumGeoms(sp);
1841  }
1842  else
1843  nstaticgeoms++;
1844  }
1845 
1846  int ntopgeoms = d.SpaceGetNumGeoms(TopSpace);
1847 
1848  int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray
1849  int nbodies = d.NTotalBodies;
1850  int ngeoms = d.NTotalGeoms;
1851 */
1852  // Finished with all sim stepping. If requested, dump world state to file for debugging.
1853  // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
1854  // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
1855  if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
1856  {
1857  string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
1858  string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
1859 
1860  if (physics_logging_append_existing_logfile)
1861  {
1862  string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
1863  TextWriter fwriter = File.AppendText(fname);
1864  fwriter.WriteLine(header);
1865  fwriter.Close();
1866  }
1867 
1868  d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
1869  }
1870 
1871  fps = (float)nodeframes * ODE_STEPSIZE / reqTimeStep;
1872 
1873  if(step_time < HalfOdeStep)
1874  m_timeDilation = 1.0f;
1875  else if (step_time > m_SkipFramesAtms)
1876  {
1877  // if we lag too much skip frames
1878  m_timeDilation = 0.0f;
1879  step_time = 0;
1880  m_lastframe = DateTime.UtcNow; // skip also the time lost
1881  }
1882  else
1883  {
1884  m_timeDilation = ODE_STEPSIZE / step_time;
1885  if (m_timeDilation > 1)
1886  m_timeDilation = 1;
1887  }
1888  }
1889 
1890  return fps;
1891  }
1892 
1894  public override void GetResults()
1895  {
1896  }
1897 
1898  public override bool IsThreaded
1899  {
1900  // for now we won't be multithreaded
1901  get { return (false); }
1902  }
1903 
1904  public float GetTerrainHeightAtXY(float x, float y)
1905  {
1906 
1907  int offsetX = 0;
1908  int offsetY = 0;
1909 
1910  if (m_suportCombine)
1911  {
1912  offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1913  offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1914  }
1915 
1916  // get region map
1917  IntPtr heightFieldGeom = IntPtr.Zero;
1918  if (!RegionTerrain.TryGetValue(new Vector3(offsetX, offsetY, 0), out heightFieldGeom))
1919  return 0f;
1920 
1921  if (heightFieldGeom == IntPtr.Zero)
1922  return 0f;
1923 
1924  if (!TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1925  return 0f;
1926 
1927  // TerrainHeightField for ODE as offset 1m
1928  x += 1f - offsetX;
1929  y += 1f - offsetY;
1930 
1931  // make position fit into array
1932  if (x < 0)
1933  x = 0;
1934  if (y < 0)
1935  y = 0;
1936 
1937  // integer indexs
1938  int ix;
1939  int iy;
1940  // interpolators offset
1941  float dx;
1942  float dy;
1943 
1944  int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples
1945  int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples
1946  int regsize = regsizeX;
1947 
1948  if (m_OSOdeLib)
1949  {
1950  if (x < regsizeX - 1)
1951  {
1952  ix = (int)x;
1953  dx = x - (float)ix;
1954  }
1955  else // out world use external height
1956  {
1957  ix = regsizeX - 2;
1958  dx = 0;
1959  }
1960  if (y < regsizeY - 1)
1961  {
1962  iy = (int)y;
1963  dy = y - (float)iy;
1964  }
1965  else
1966  {
1967  iy = regsizeY - 2;
1968  dy = 0;
1969  }
1970  }
1971  else
1972  {
1973  // we still have square fixed size regions
1974  // also flip x and y because of how map is done for ODE fliped axis
1975  // so ix,iy,dx and dy are inter exchanged
1976 
1977  regsize = regsizeY;
1978 
1979  if (x < regsizeX - 1)
1980  {
1981  iy = (int)x;
1982  dy = x - (float)iy;
1983  }
1984  else // out world use external height
1985  {
1986  iy = regsizeX - 2;
1987  dy = 0;
1988  }
1989  if (y < regsizeY - 1)
1990  {
1991  ix = (int)y;
1992  dx = y - (float)ix;
1993  }
1994  else
1995  {
1996  ix = regsizeY - 2;
1997  dx = 0;
1998  }
1999  }
2000 
2001  float h0;
2002  float h1;
2003  float h2;
2004 
2005  iy *= regsize;
2006  iy += ix; // all indexes have iy + ix
2007 
2008  float[] heights = TerrainHeightFieldHeights[heightFieldGeom];
2009  /*
2010  if ((dx + dy) <= 1.0f)
2011  {
2012  h0 = ((float)heights[iy]); // 0,0 vertice
2013  h1 = (((float)heights[iy + 1]) - h0) * dx; // 1,0 vertice minus 0,0
2014  h2 = (((float)heights[iy + regsize]) - h0) * dy; // 0,1 vertice minus 0,0
2015  }
2016  else
2017  {
2018  h0 = ((float)heights[iy + regsize + 1]); // 1,1 vertice
2019  h1 = (((float)heights[iy + 1]) - h0) * (1 - dy); // 1,1 vertice minus 1,0
2020  h2 = (((float)heights[iy + regsize]) - h0) * (1 - dx); // 1,1 vertice minus 0,1
2021  }
2022  */
2023  h0 = ((float)heights[iy]); // 0,0 vertice
2024 
2025  if (dy>dx)
2026  {
2027  iy += regsize;
2028  h2 = (float)heights[iy]; // 0,1 vertice
2029  h1 = (h2 - h0) * dy; // 0,1 vertice minus 0,0
2030  h2 = ((float)heights[iy + 1] - h2) * dx; // 1,1 vertice minus 0,1
2031  }
2032  else
2033  {
2034  iy++;
2035  h2 = (float)heights[iy]; // vertice 1,0
2036  h1 = (h2 - h0) * dx; // 1,0 vertice minus 0,0
2037  h2 = (((float)heights[iy + regsize]) - h2) * dy; // 1,1 vertice minus 1,0
2038  }
2039 
2040  return h0 + h1 + h2;
2041  }
2042 
2043  public Vector3 GetTerrainNormalAtXY(float x, float y)
2044  {
2045  int offsetX = 0;
2046  int offsetY = 0;
2047 
2048  if (m_suportCombine)
2049  {
2050  offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
2051  offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
2052  }
2053 
2054  // get region map
2055  IntPtr heightFieldGeom = IntPtr.Zero;
2056  Vector3 norm = new Vector3(0, 0, 1);
2057 
2058  if (!RegionTerrain.TryGetValue(new Vector3(offsetX, offsetY, 0), out heightFieldGeom))
2059  return norm; ;
2060 
2061  if (heightFieldGeom == IntPtr.Zero)
2062  return norm;
2063 
2064  if (!TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
2065  return norm;
2066 
2067  // TerrainHeightField for ODE as offset 1m
2068  x += 1f - offsetX;
2069  y += 1f - offsetY;
2070 
2071  // make position fit into array
2072  if (x < 0)
2073  x = 0;
2074  if (y < 0)
2075  y = 0;
2076 
2077  // integer indexs
2078  int ix;
2079  int iy;
2080  // interpolators offset
2081  float dx;
2082  float dy;
2083 
2084  int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples
2085  int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples
2086  int regsize = regsizeX;
2087 
2088  int xstep = 1;
2089  int ystep = regsizeX;
2090  bool firstTri = false;
2091 
2092  if (m_OSOdeLib)
2093  {
2094  if (x < regsizeX - 1)
2095  {
2096  ix = (int)x;
2097  dx = x - (float)ix;
2098  }
2099  else // out world use external height
2100  {
2101  ix = regsizeX - 2;
2102  dx = 0;
2103  }
2104  if (y < regsizeY - 1)
2105  {
2106  iy = (int)y;
2107  dy = y - (float)iy;
2108  }
2109  else
2110  {
2111  iy = regsizeY - 2;
2112  dy = 0;
2113  }
2114  firstTri = dy > dx;
2115  }
2116 
2117  else
2118  {
2119  xstep = regsizeY;
2120  ystep = 1;
2121  regsize = regsizeY;
2122 
2123  // we still have square fixed size regions
2124  // also flip x and y because of how map is done for ODE fliped axis
2125  // so ix,iy,dx and dy are inter exchanged
2126  if (x < regsizeX - 1)
2127  {
2128  iy = (int)x;
2129  dy = x - (float)iy;
2130  }
2131  else // out world use external height
2132  {
2133  iy = regsizeX - 2;
2134  dy = 0;
2135  }
2136  if (y < regsizeY - 1)
2137  {
2138  ix = (int)y;
2139  dx = y - (float)ix;
2140  }
2141  else
2142  {
2143  ix = regsizeY - 2;
2144  dx = 0;
2145  }
2146  firstTri = dx > dy;
2147  }
2148 
2149  float h0;
2150  float h1;
2151  float h2;
2152 
2153  iy *= regsize;
2154  iy += ix; // all indexes have iy + ix
2155 
2156  float[] heights = TerrainHeightFieldHeights[heightFieldGeom];
2157 
2158  if (firstTri)
2159  {
2160  h1 = ((float)heights[iy]); // 0,0 vertice
2161  iy += ystep;
2162  h0 = (float)heights[iy]; // 0,1
2163  h2 = (float)heights[iy+xstep]; // 1,1 vertice
2164  norm.X = h0 - h2;
2165  norm.Y = h1 - h0;
2166  }
2167  else
2168  {
2169  h2 = ((float)heights[iy]); // 0,0 vertice
2170  iy += xstep;
2171  h0 = ((float)heights[iy]); // 1,0 vertice
2172  h1 = (float)heights[iy+ystep]; // vertice 1,1
2173  norm.X = h2 - h0;
2174  norm.Y = h0 - h1;
2175  }
2176  norm.Z = 1;
2177  norm.Normalize();
2178  return norm;
2179  }
2180 
2181  public override void SetTerrain(float[] heightMap)
2182  {
2183  if (m_worldOffset != Vector3.Zero && m_parentScene != null)
2184  {
2185  if (m_parentScene is ODEScene)
2186  {
2187  ((ODEScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
2188  }
2189  }
2190  else
2191  {
2192  SetTerrain(heightMap, m_worldOffset);
2193  }
2194  }
2195 
2196  public override void CombineTerrain(float[] heightMap, Vector3 pOffset)
2197  {
2198  if(m_suportCombine)
2199  SetTerrain(heightMap, pOffset);
2200  }
2201 
2202  public void SetTerrain(float[] heightMap, Vector3 pOffset)
2203  {
2204  if (m_OSOdeLib)
2205  OSSetTerrain(heightMap, pOffset);
2206  else
2207  OriSetTerrain(heightMap, pOffset);
2208  }
2209 
2210  public void OriSetTerrain(float[] heightMap, Vector3 pOffset)
2211  {
2212  // assumes 1m size grid and constante size square regions
2213  // needs to know about sims around in future
2214 
2215  float[] _heightmap;
2216 
2217  uint regionsizeX = m_regionWidth;
2218  uint regionsizeY = m_regionHeight;
2219 
2220  // map is rotated
2221  uint heightmapWidth = regionsizeY + 2;
2222  uint heightmapHeight = regionsizeX + 2;
2223 
2224  uint heightmapWidthSamples = heightmapWidth + 1;
2225  uint heightmapHeightSamples = heightmapHeight + 1;
2226 
2227  _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
2228 
2229  const float scale = 1.0f;
2230  const float offset = 0.0f;
2231  const float thickness = 10f;
2232  const int wrap = 0;
2233 
2234 
2235  float hfmin = float.MaxValue;
2236  float hfmax = float.MinValue;
2237  float val;
2238  uint xx;
2239  uint yy;
2240 
2241  uint maxXX = regionsizeX - 1;
2242  uint maxYY = regionsizeY - 1;
2243  // flipping map adding one margin all around so things don't fall in edges
2244 
2245  uint xt = 0;
2246  xx = 0;
2247 
2248  for (uint x = 0; x < heightmapWidthSamples; x++)
2249  {
2250  if (x > 1 && xx < maxXX)
2251  xx++;
2252  yy = 0;
2253  for (uint y = 0; y < heightmapHeightSamples; y++)
2254  {
2255  if (y > 1 && y < maxYY)
2256  yy += regionsizeX;
2257 
2258  val = heightMap[yy + xx];
2259  if (val < 0.0f)
2260  val = 0.0f; // no neg terrain as in chode
2261  _heightmap[xt + y] = val;
2262 
2263  if (hfmin > val)
2264  hfmin = val;
2265  if (hfmax < val)
2266  hfmax = val;
2267  }
2268  xt += heightmapHeightSamples;
2269  }
2270 
2271  lock (OdeLock)
2272  {
2273  d.AllocateODEDataForThread(~0U);
2274 
2275  IntPtr GroundGeom = IntPtr.Zero;
2276  if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
2277  {
2278  RegionTerrain.Remove(pOffset);
2279  if (GroundGeom != IntPtr.Zero)
2280  {
2281  actor_name_map.Remove(GroundGeom);
2282  d.GeomDestroy(GroundGeom);
2283 
2284  if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
2285  {
2286  TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
2287  TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
2288  TerrainHeightFieldHeights.Remove(GroundGeom);
2289  }
2290  }
2291  }
2292  IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
2293 
2294  GCHandle _heightmaphandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
2295 
2296  d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmaphandler.AddrOfPinnedObject(), 0,
2297  heightmapHeight, heightmapWidth ,
2298  (int)heightmapHeightSamples, (int)heightmapWidthSamples, scale,
2299  offset, thickness, wrap);
2300 
2301  d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
2302 
2303  GroundGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1);
2304 
2305  if (GroundGeom != IntPtr.Zero)
2306  {
2307  d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
2308  d.GeomSetCollideBits(GroundGeom, 0);
2309 
2310  PhysicsActor pa = new NullPhysicsActor();
2311  pa.Name = "Terrain";
2312  pa.PhysicsActorType = (int)ActorTypes.Ground;
2313  actor_name_map[GroundGeom] = pa;
2314 
2315 // geom_name_map[GroundGeom] = "Terrain";
2316 
2317  d.Quaternion q = new d.Quaternion();
2318  q.X = 0.5f;
2319  q.Y = 0.5f;
2320  q.Z = 0.5f;
2321  q.W = 0.5f;
2322 
2323  d.GeomSetQuaternion(GroundGeom, ref q);
2324  d.GeomSetPosition(GroundGeom, pOffset.X + m_regionWidth * 0.5f, pOffset.Y + m_regionHeight * 0.5f, 0.0f);
2325  RegionTerrain.Add(pOffset, GroundGeom);
2326  TerrainHeightFieldHeights.Add(GroundGeom, _heightmap);
2327  TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler);
2328  }
2329  }
2330  }
2331 
2332  public void OSSetTerrain(float[] heightMap, Vector3 pOffset)
2333  {
2334  // assumes 1m size grid and constante size square regions
2335  // needs to know about sims around in future
2336 
2337  float[] _heightmap;
2338 
2339  uint regionsizeX = m_regionWidth;
2340  uint regionsizeY = m_regionHeight;
2341 
2342  uint heightmapWidth = regionsizeX + 2;
2343  uint heightmapHeight = regionsizeY + 2;
2344 
2345  uint heightmapWidthSamples = heightmapWidth + 1;
2346  uint heightmapHeightSamples = heightmapHeight + 1;
2347 
2348  _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
2349 
2350 
2351  float hfmin = float.MaxValue;
2352 // float hfmax = float.MinValue;
2353  float val;
2354 
2355 
2356  uint maxXX = regionsizeX - 1;
2357  uint maxYY = regionsizeY - 1;
2358  // adding one margin all around so things don't fall in edges
2359 
2360  uint xx;
2361  uint yy = 0;
2362  uint yt = 0;
2363 
2364  for (uint y = 0; y < heightmapHeightSamples; y++)
2365  {
2366  if (y > 1 && y < maxYY)
2367  yy += regionsizeX;
2368  xx = 0;
2369  for (uint x = 0; x < heightmapWidthSamples; x++)
2370  {
2371  if (x > 1 && x < maxXX)
2372  xx++;
2373 
2374  val = heightMap[yy + xx];
2375  if (val < 0.0f)
2376  val = 0.0f; // no neg terrain as in chode
2377  _heightmap[yt + x] = val;
2378 
2379  if (hfmin > val)
2380  hfmin = val;
2381 // if (hfmax < val)
2382 // hfmax = val;
2383  }
2384  yt += heightmapWidthSamples;
2385  }
2386  lock (OdeLock)
2387  {
2388  IntPtr GroundGeom = IntPtr.Zero;
2389  if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
2390  {
2391  RegionTerrain.Remove(pOffset);
2392  if (GroundGeom != IntPtr.Zero)
2393  {
2394  actor_name_map.Remove(GroundGeom);
2395  d.GeomDestroy(GroundGeom);
2396 
2397  if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
2398  {
2399  if (TerrainHeightFieldHeightsHandlers[GroundGeom].IsAllocated)
2400  TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
2401  TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
2402  TerrainHeightFieldHeights.Remove(GroundGeom);
2403  }
2404  }
2405  }
2406  IntPtr HeightmapData = d.GeomOSTerrainDataCreate();
2407 
2408  const int wrap = 0;
2409  float thickness = hfmin;
2410  if (thickness < 0)
2411  thickness = 1;
2412 
2413  GCHandle _heightmaphandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
2414 
2415  d.GeomOSTerrainDataBuild(HeightmapData, _heightmaphandler.AddrOfPinnedObject(), 0, 1.0f,
2416  (int)heightmapWidthSamples, (int)heightmapHeightSamples,
2417  thickness, wrap);
2418 
2419 // d.GeomOSTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
2420  GroundGeom = d.CreateOSTerrain(GroundSpace, HeightmapData, 1);
2421  if (GroundGeom != IntPtr.Zero)
2422  {
2423  d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
2424  d.GeomSetCollideBits(GroundGeom, 0);
2425 
2426 
2427  PhysicsActor pa = new NullPhysicsActor();
2428  pa.Name = "Terrain";
2429  pa.PhysicsActorType = (int)ActorTypes.Ground;
2430  actor_name_map[GroundGeom] = pa;
2431 
2432 // geom_name_map[GroundGeom] = "Terrain";
2433 
2434  d.GeomSetPosition(GroundGeom, pOffset.X + m_regionWidth * 0.5f, pOffset.Y + m_regionHeight * 0.5f, 0.0f);
2435  RegionTerrain.Add(pOffset, GroundGeom);
2436  TerrainHeightFieldHeights.Add(GroundGeom, _heightmap);
2437  TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler);
2438  }
2439  }
2440  }
2441 
2442  public override void DeleteTerrain()
2443  {
2444  }
2445 
2446  public float GetWaterLevel()
2447  {
2448  return waterlevel;
2449  }
2450 
2451  public override bool SupportsCombining()
2452  {
2453  return m_suportCombine;
2454  }
2455 
2456  public override void SetWaterLevel(float baseheight)
2457  {
2458  waterlevel = baseheight;
2459  }
2460 
2461  public override void Dispose()
2462  {
2463  lock (OdeLock)
2464  {
2465 
2466  if (world == IntPtr.Zero)
2467  return;
2468 
2469  d.AllocateODEDataForThread(~0U);
2470 
2471  if (m_meshWorker != null)
2472  m_meshWorker.Stop();
2473 
2474  if (m_rayCastManager != null)
2475  {
2476  m_rayCastManager.Dispose();
2477  m_rayCastManager = null;
2478  }
2479 
2480  lock (_prims)
2481  {
2482  ChangesQueue.Clear();
2483  foreach (OdePrim prm in _prims)
2484  {
2485  prm.DoAChange(changes.Remove, null);
2486  _collisionEventPrim.Remove(prm);
2487  }
2488  _prims.Clear();
2489  }
2490 
2491  OdeCharacter[] chtorem;
2492  lock (_characters)
2493  {
2494  chtorem = new OdeCharacter[_characters.Count];
2495  _characters.CopyTo(chtorem);
2496  }
2497 
2498  ChangesQueue.Clear();
2499  foreach (OdeCharacter ch in chtorem)
2500  ch.DoAChange(changes.Remove, null);
2501 
2502 
2503  foreach (IntPtr GroundGeom in RegionTerrain.Values)
2504  {
2505  if (GroundGeom != IntPtr.Zero)
2506  d.GeomDestroy(GroundGeom);
2507  }
2508 
2509  RegionTerrain.Clear();
2510 
2511  if (TerrainHeightFieldHeightsHandlers.Count > 0)
2512  {
2513  foreach (GCHandle gch in TerrainHeightFieldHeightsHandlers.Values)
2514  {
2515  if (gch.IsAllocated)
2516  gch.Free();
2517  }
2518  }
2519 
2520  TerrainHeightFieldHeightsHandlers.Clear();
2521  TerrainHeightFieldHeights.Clear();
2522 
2523  if (ContactgeomsArray != IntPtr.Zero)
2524  {
2525  Marshal.FreeHGlobal(ContactgeomsArray);
2526  ContactgeomsArray = IntPtr.Zero;
2527  }
2528  if (GlobalContactsArray != IntPtr.Zero)
2529  {
2530  Marshal.FreeHGlobal(GlobalContactsArray);
2531  GlobalContactsArray = IntPtr.Zero;
2532  }
2533 
2534  d.WorldDestroy(world);
2535  world = IntPtr.Zero;
2536  //d.CloseODE();
2537  }
2538  }
2539 
2540  public override Dictionary<uint, float> GetTopColliders()
2541  {
2542  Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
2543  int cnt = 0;
2544  lock (_prims)
2545  {
2546  foreach (OdePrim prm in _prims)
2547  {
2548  if (prm.CollisionScore > 0)
2549  {
2550  returncolliders.Add(prm.LocalID, prm.CollisionScore);
2551  cnt++;
2552  prm.CollisionScore = 0f;
2553  if (cnt > 25)
2554  {
2555  break;
2556  }
2557  }
2558  }
2559  }
2560  return returncolliders;
2561  }
2562 
2563  public override bool SupportsRayCast()
2564  {
2565  return true;
2566  }
2567 
2568  public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
2569  {
2570  if (retMethod != null)
2571  {
2572  ODERayRequest req = new ODERayRequest();
2573  req.actor = null;
2574  req.callbackMethod = retMethod;
2575  req.length = length;
2576  req.Normal = direction;
2577  req.Origin = position;
2578  req.Count = 0;
2579  req.filter = RayFilterFlags.AllPrims;
2580 
2581  m_rayCastManager.QueueRequest(req);
2582  }
2583  }
2584 
2585  public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
2586  {
2587  if (retMethod != null)
2588  {
2589  ODERayRequest req = new ODERayRequest();
2590  req.actor = null;
2591  req.callbackMethod = retMethod;
2592  req.length = length;
2593  req.Normal = direction;
2594  req.Origin = position;
2595  req.Count = Count;
2596  req.filter = RayFilterFlags.AllPrims;
2597 
2598  m_rayCastManager.QueueRequest(req);
2599  }
2600  }
2601 
2602 
2603  public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
2604  {
2605  List<ContactResult> ourresults = new List<ContactResult>();
2606  object SyncObject = new object();
2607 
2608  RayCallback retMethod = delegate(List<ContactResult> results)
2609  {
2610  lock (SyncObject)
2611  {
2612  ourresults = results;
2613  Monitor.PulseAll(SyncObject);
2614  }
2615  };
2616 
2617  ODERayRequest req = new ODERayRequest();
2618  req.actor = null;
2619  req.callbackMethod = retMethod;
2620  req.length = length;
2621  req.Normal = direction;
2622  req.Origin = position;
2623  req.Count = Count;
2624  req.filter = RayFilterFlags.AllPrims;
2625 
2626  lock (SyncObject)
2627  {
2628  m_rayCastManager.QueueRequest(req);
2629  if (!Monitor.Wait(SyncObject, 500))
2630  return null;
2631  else
2632  return ourresults;
2633  }
2634  }
2635 
2636  public override bool SupportsRaycastWorldFiltered()
2637  {
2638  return true;
2639  }
2640 
2641  public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
2642  {
2643  object SyncObject = new object();
2644  List<ContactResult> ourresults = new List<ContactResult>();
2645 
2646  RayCallback retMethod = delegate(List<ContactResult> results)
2647  {
2648  lock (SyncObject)
2649  {
2650  ourresults = results;
2651  Monitor.PulseAll(SyncObject);
2652  }
2653  };
2654 
2655  ODERayRequest req = new ODERayRequest();
2656  req.actor = null;
2657  req.callbackMethod = retMethod;
2658  req.length = length;
2659  req.Normal = direction;
2660  req.Origin = position;
2661  req.Count = Count;
2662  req.filter = filter;
2663 
2664  lock (SyncObject)
2665  {
2666  m_rayCastManager.QueueRequest(req);
2667  if (!Monitor.Wait(SyncObject, 500))
2668  return null;
2669  else
2670  return ourresults;
2671  }
2672  }
2673 
2674  public override List<ContactResult> RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags flags)
2675  {
2676  if (actor == null)
2677  return new List<ContactResult>();
2678 
2679  IntPtr geom;
2680  if (actor is OdePrim)
2681  geom = ((OdePrim)actor).prim_geom;
2682  else if (actor is OdeCharacter)
2683  geom = ((OdePrim)actor).prim_geom;
2684  else
2685  return new List<ContactResult>();
2686 
2687  if (geom == IntPtr.Zero)
2688  return new List<ContactResult>();
2689 
2690  List<ContactResult> ourResults = null;
2691  object SyncObject = new object();
2692 
2693  RayCallback retMethod = delegate(List<ContactResult> results)
2694  {
2695  lock (SyncObject)
2696  {
2697  ourResults = results;
2698  Monitor.PulseAll(SyncObject);
2699  }
2700  };
2701 
2702  ODERayRequest req = new ODERayRequest();
2703  req.actor = actor;
2704  req.callbackMethod = retMethod;
2705  req.length = length;
2706  req.Normal = direction;
2707  req.Origin = position;
2708  req.Count = Count;
2709  req.filter = flags;
2710 
2711  lock (SyncObject)
2712  {
2713  m_rayCastManager.QueueRequest(req);
2714  if (!Monitor.Wait(SyncObject, 500))
2715  return new List<ContactResult>();
2716  }
2717 
2718  if (ourResults == null)
2719  return new List<ContactResult>();
2720  return ourResults;
2721  }
2722 
2723  public override List<ContactResult> BoxProbe(Vector3 position, Vector3 size, Quaternion orientation, int Count, RayFilterFlags flags)
2724  {
2725  List<ContactResult> ourResults = null;
2726  object SyncObject = new object();
2727 
2728  ProbeBoxCallback retMethod = delegate(List<ContactResult> results)
2729  {
2730  lock (SyncObject)
2731  {
2732  ourResults = results;
2733  Monitor.PulseAll(SyncObject);
2734  }
2735  };
2736 
2737  ODERayRequest req = new ODERayRequest();
2738  req.actor = null;
2739  req.callbackMethod = retMethod;
2740  req.Normal = size;
2741  req.Origin = position;
2742  req.orientation = orientation;
2743  req.Count = Count;
2744  req.filter = flags;
2745 
2746  lock (SyncObject)
2747  {
2748  m_rayCastManager.QueueRequest(req);
2749  if (!Monitor.Wait(SyncObject, 500))
2750  return new List<ContactResult>();
2751  }
2752 
2753  if (ourResults == null)
2754  return new List<ContactResult>();
2755  return ourResults;
2756  }
2757 
2758  public override List<ContactResult> SphereProbe(Vector3 position, float radius, int Count, RayFilterFlags flags)
2759  {
2760  List<ContactResult> ourResults = null;
2761  object SyncObject = new object();
2762 
2763  ProbeSphereCallback retMethod = delegate(List<ContactResult> results)
2764  {
2765  ourResults = results;
2766  Monitor.PulseAll(SyncObject);
2767  };
2768 
2769  ODERayRequest req = new ODERayRequest();
2770  req.actor = null;
2771  req.callbackMethod = retMethod;
2772  req.length = radius;
2773  req.Origin = position;
2774  req.Count = Count;
2775  req.filter = flags;
2776 
2777 
2778  lock (SyncObject)
2779  {
2780  m_rayCastManager.QueueRequest(req);
2781  if (!Monitor.Wait(SyncObject, 500))
2782  return new List<ContactResult>();
2783  }
2784 
2785  if (ourResults == null)
2786  return new List<ContactResult>();
2787  return ourResults;
2788  }
2789 
2790  public override List<ContactResult> PlaneProbe(PhysicsActor actor, Vector4 plane, int Count, RayFilterFlags flags)
2791  {
2792  IntPtr geom = IntPtr.Zero;;
2793 
2794  if (actor != null)
2795  {
2796  if (actor is OdePrim)
2797  geom = ((OdePrim)actor).prim_geom;
2798  else if (actor is OdeCharacter)
2799  geom = ((OdePrim)actor).prim_geom;
2800  }
2801 
2802  List<ContactResult> ourResults = null;
2803  object SyncObject = new object();
2804 
2805  ProbePlaneCallback retMethod = delegate(List<ContactResult> results)
2806  {
2807  ourResults = results;
2808  Monitor.PulseAll(SyncObject);
2809  };
2810 
2811  ODERayRequest req = new ODERayRequest();
2812  req.actor = null;
2813  req.callbackMethod = retMethod;
2814  req.length = plane.W;
2815  req.Normal.X = plane.X;
2816  req.Normal.Y = plane.Y;
2817  req.Normal.Z = plane.Z;
2818  req.Count = Count;
2819  req.filter = flags;
2820 
2821  lock (SyncObject)
2822  {
2823  m_rayCastManager.QueueRequest(req);
2824  if (!Monitor.Wait(SyncObject, 500))
2825  return new List<ContactResult>();
2826  }
2827 
2828  if (ourResults == null)
2829  return new List<ContactResult>();
2830  return ourResults;
2831  }
2832 
2833  public override int SitAvatar(PhysicsActor actor, Vector3 AbsolutePosition, Vector3 CameraPosition, Vector3 offset, Vector3 AvatarSize, SitAvatarCallback PhysicsSitResponse)
2834  {
2835  Util.FireAndForget( delegate
2836  {
2837  ODESitAvatar sitAvatar = new ODESitAvatar(this, m_rayCastManager);
2838  if(sitAvatar != null)
2839  sitAvatar.Sit(actor, AbsolutePosition, CameraPosition, offset, AvatarSize, PhysicsSitResponse);
2840  });
2841  return 1;
2842  }
2843 
2844  }
2845 }
override List< ContactResult > PlaneProbe(PhysicsActor actor, Vector4 plane, int Count, RayFilterFlags flags)
Definition: ODEScene.cs:2790
void SetTerrain(float[] heightMap, Vector3 pOffset)
Definition: ODEScene.cs:2202
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:2568
override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
Definition: ODEScene.cs:2641
IntPtr calculateSpaceForGeom(Vector3 pos)
Calculates the space the prim should be in by its position
Definition: ODEScene.cs:1497
override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
Definition: ODEScene.cs:1342
Processes raycast requests as ODE is in a state to be able to do them. This ensures that it's thread ...
void addActiveGroups(OdePrim activatePrim)
Definition: ODEScene.cs:1312
override List< ContactResult > SphereProbe(Vector3 position, float radius, int Count, RayFilterFlags flags)
Definition: ODEScene.cs:2758
override int SitAvatar(PhysicsActor actor, Vector3 AbsolutePosition, Vector3 CameraPosition, Vector3 offset, Vector3 AvatarSize, SitAvatarCallback PhysicsSitResponse)
Definition: ODEScene.cs:2833
override bool IsPhysical
Is this prim subject to physics? Even if not, it's still solid for collision purposes.
Definition: ODEPrim.cs:211
void remActivePrim(OdePrim deactivatePrim)
Definition: ODEScene.cs:1355
delegate void ProbePlaneCallback(List< ContactResult > list)
delegate void RayCallback(List< ContactResult > list)
bool haveActor(PhysicsActor actor)
Definition: ODEScene.cs:1403
IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace)
Called when a static prim moves or becomes static Places the prim in a space one the static sub-space...
Definition: ODEScene.cs:1430
override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, float feetOffset, bool isFlying)
Definition: ODEScene.cs:1248
void remActiveGroup(OdePrim deactivatePrim)
Definition: ODEScene.cs:1362
delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal)
override void RemoveAvatar(PhysicsActor actor)
Remove an avatar.
Definition: ODEScene.cs:1291
override void SetWaterLevel(float baseheight)
Definition: ODEScene.cs:2456
Vector3 GetTerrainNormalAtXY(float x, float y)
Definition: ODEScene.cs:2043
override void RemovePrim(PhysicsActor prim)
Remove a prim.
Definition: ODEScene.cs:1370
float GetTerrainHeightAtXY(float x, float y)
Definition: ODEScene.cs:1904
delegate void ProbeBoxCallback(List< ContactResult > list)
void OSSetTerrain(float[] heightMap, Vector3 pOffset)
Definition: ODEScene.cs:2332
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
override void SetTerrain(float[] heightMap)
Definition: ODEScene.cs:2181
override List< ContactResult > RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
Definition: ODEScene.cs:2603
override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
Definition: ODEScene.cs:2585
void RemoveCollisionEventReporting(PhysicsActor obj)
Remove actor from the list that should receive collision events in the simulate loop.
Definition: ODEScene.cs:1225
override bool SupportsRayCast()
True if the physics plugin supports raycasting against the physics scene
Definition: ODEScene.cs:2563
override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid)
Definition: ODEScene.cs:1348
void addActivePrim(OdePrim activatePrim)
Definition: ODEScene.cs:1302
delegate void ProbeSphereCallback(List< ContactResult > list)
override float Simulate(float reqTimeStep)
This is our main simulate loop It's thread locked by a Mutex in the scene. It holds Collisions...
Definition: ODEScene.cs:1601
ODEScene(Scene pscene, IConfigSource psourceconfig, string pname, bool pOSOdeLib)
Definition: ODEScene.cs:327
void RemoveCharacter(OdeCharacter chr)
Definition: ODEScene.cs:1271
delegate void SitAvatarCallback(int status, uint partID, Vector3 offset, Quaternion Orientation)
void OriSetTerrain(float[] heightMap, Vector3 pOffset)
Definition: ODEScene.cs:2210
override List< ContactResult > BoxProbe(Vector3 position, Vector3 size, Quaternion orientation, int Count, RayFilterFlags flags)
Definition: ODEScene.cs:2723
Material
Material type for a primitive
Definition: ODEScene.cs:80
override List< ContactResult > RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags flags)
Definition: ODEScene.cs:2674
override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
Add an avatar
Definition: ODEScene.cs:1243
override void CombineTerrain(float[] heightMap, Vector3 pOffset)
Definition: ODEScene.cs:2196
override void AddPhysicsActorTaint(PhysicsActor prim)
Called after our prim properties are set Scale, position etc. We use this event queue like method to ...
Definition: ODEScene.cs:1541
override Dictionary< uint, float > GetTopColliders()
Definition: ODEScene.cs:2540
void AddChange(PhysicsActor actor, changes what, Object arg)
Called to queue a change to a actor to use in place of old taint mechanism so changes do have a time ...
Definition: ODEScene.cs:1526