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