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