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