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