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.cs2898
1 files changed, 2898 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..7848b35
--- /dev/null
+++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
@@ -0,0 +1,2898 @@
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
717 count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
718 }
719 catch (SEHException)
720 {
721 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.");
722// ode.drelease(world);
723 base.TriggerPhysicsBasedRestart();
724 }
725 catch (Exception e)
726 {
727 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
728 return;
729 }
730
731 // id contacts done
732 if (count == 0)
733 return;
734
735 // try get physical actors
736 PhysicsActor p1;
737 PhysicsActor p2;
738
739 if (!actor_name_map.TryGetValue(g1, out p1))
740 {
741 p1 = PANull;
742 }
743
744 if (!actor_name_map.TryGetValue(g2, out p2))
745 {
746 p2 = PANull;
747 }
748
749 // update actors collision score
750 if (p1.CollisionScore >= float.MaxValue - count)
751 p1.CollisionScore = 0;
752 p1.CollisionScore += count;
753
754 if (p2.CollisionScore >= float.MaxValue - count)
755 p2.CollisionScore = 0;
756 p2.CollisionScore += count;
757
758
759 // get first contact
760 d.ContactGeom curContact = new d.ContactGeom();
761 if (!GetCurContactGeom(0, ref curContact))
762 return;
763 // for now it's the one with max depth
764 ContactPoint maxDepthContact = new ContactPoint(
765 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
766 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
767 curContact.depth
768 );
769 // do volume detection case
770 if (
771 (p1.IsVolumeDtc || p2.IsVolumeDtc))
772 {
773 collision_accounting_events(p1, p2, maxDepthContact);
774 return;
775 }
776
777 // big messy collision analises
778
779 Vector3 normoverride = Vector3.Zero; //damm c#
780
781 float mu = 0;
782 float bounce = 0;
783 float cfm = 0.0001f;
784 float erpscale = 1.0f;
785 float dscale = 1.0f;
786 bool IgnoreNegSides = false;
787
788 ContactData contactdata1 = new ContactData(0, 0, false);
789 ContactData contactdata2 = new ContactData(0, 0, false);
790
791 String name = null;
792 bool dop1foot = false;
793 bool dop2foot = false;
794 bool ignore = false;
795 bool AvanormOverride = false;
796
797 switch (p1.PhysicsActorType)
798 {
799 case (int)ActorTypes.Agent:
800 {
801 AvanormOverride = true;
802 Vector3 tmp = p2.Position - p1.Position;
803 normoverride = p2.Velocity - p1.Velocity;
804 mu = normoverride.LengthSquared();
805
806 if (mu > 1e-6)
807 {
808 mu = 1.0f / (float)Math.Sqrt(mu);
809 normoverride *= mu;
810 mu = Vector3.Dot(tmp, normoverride);
811 if (mu > 0)
812 normoverride *= -1;
813 }
814 else
815 {
816 tmp.Normalize();
817 normoverride = -tmp;
818 }
819
820 switch (p2.PhysicsActorType)
821 {
822 case (int)ActorTypes.Agent:
823/*
824 p1.getContactData(ref contactdata1);
825 p2.getContactData(ref contactdata2);
826
827 mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);
828
829 if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f))
830 mu *= frictionMovementMult;
831*/
832 p1.CollidingObj = true;
833 p2.CollidingObj = true;
834 break;
835 case (int)ActorTypes.Prim:
836/*
837 p1.getContactData(ref contactdata1);
838 p2.getContactData(ref contactdata2);
839
840
841 mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);
842
843 if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f))
844 mu *= frictionMovementMult;
845 */
846 if (p2.Velocity.LengthSquared() > 0.0f)
847 p2.CollidingObj = true;
848
849 dop1foot = true;
850 break;
851 default:
852 ignore = true; // avatar to terrain and water ignored
853 break;
854 }
855 break;
856 }
857
858 case (int)ActorTypes.Prim:
859 switch (p2.PhysicsActorType)
860 {
861 case (int)ActorTypes.Agent:
862 // p1.getContactData(ref contactdata1);
863 // p2.getContactData(ref contactdata2);
864
865 AvanormOverride = true;
866
867 Vector3 tmp = p2.Position - p1.Position;
868 normoverride = p2.Velocity - p1.Velocity;
869 mu = normoverride.LengthSquared();
870 if (mu > 1e-6)
871 {
872 mu = 1.0f / (float)Math.Sqrt(mu);
873 normoverride *= mu;
874 mu = Vector3.Dot(tmp, normoverride);
875 if (mu > 0)
876 normoverride *= -1;
877 }
878 else
879 {
880 tmp.Normalize();
881 normoverride = -tmp;
882 }
883
884 bounce = 0;
885 mu = 0;
886 cfm = 0.0001f;
887 /*
888 mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);
889
890 if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f))
891 mu *= frictionMovementMult;
892 */
893 dop2foot = true;
894 if (p1.Velocity.LengthSquared() > 0.0f)
895 p1.CollidingObj = true;
896 break;
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 default:
927 if (geom_name_map.TryGetValue(g2, out name))
928 {
929 if (name == "Terrain")
930 {
931 p1.getContactData(ref contactdata1);
932 bounce = contactdata1.bounce * TerrainBounce;
933 mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction);
934 if (Math.Abs(p1.Velocity.X) > 0.1f || Math.Abs(p1.Velocity.Y) > 0.1f)
935 mu *= frictionMovementMult;
936 p1.CollidingGround = true;
937
938 cfm = p1.Mass;
939 dscale = 10 / cfm;
940 dscale = (float)Math.Sqrt(dscale);
941 if (dscale > 1.0f)
942 dscale = 1.0f;
943 erpscale = cfm * 0.01f;
944 cfm = 0.0001f / cfm;
945 if (cfm > 0.01f)
946 cfm = 0.01f;
947 else if (cfm < 0.00001f)
948 cfm = 0.00001f;
949
950 if (d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
951 {
952 if (curContact.side1 > 0)
953 IgnoreNegSides = true;
954 }
955
956 }
957 else if (name == "Water")
958 {
959 ignore = true;
960 }
961 }
962 else
963 ignore = true;
964 break;
965 }
966 break;
967
968 default:
969 if (geom_name_map.TryGetValue(g1, out name))
970 {
971 if (name == "Terrain")
972 {
973 if (p2.PhysicsActorType == (int)ActorTypes.Prim)
974 {
975 p2.CollidingGround = true;
976 p2.getContactData(ref contactdata2);
977 bounce = contactdata2.bounce * TerrainBounce;
978 mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction);
979
980 cfm = p2.Mass;
981 dscale = 10 / cfm;
982 dscale = (float)Math.Sqrt(dscale);
983
984 if (dscale > 1.0f)
985 dscale = 1.0f;
986
987 erpscale = cfm * 0.01f;
988 cfm = 0.0001f / cfm;
989 if (cfm > 0.01f)
990 cfm = 0.01f;
991 else if (cfm < 0.00001f)
992 cfm = 0.00001f;
993
994 if (curContact.side1 > 0) // should be 2 ?
995 IgnoreNegSides = true;
996
997 if (Math.Abs(p2.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y) > 0.1f)
998 mu *= frictionMovementMult;
999 }
1000 else
1001 ignore = true;
1002
1003 }
1004 else if (name == "Water" &&
1005 (p2.PhysicsActorType == (int)ActorTypes.Prim || p2.PhysicsActorType == (int)ActorTypes.Agent))
1006 {
1007 ignore = true;
1008 }
1009 }
1010 else
1011 ignore = true;
1012 break;
1013 }
1014
1015 if (ignore)
1016 return;
1017
1018 IntPtr Joint;
1019
1020 int i = 0;
1021 while(true)
1022 {
1023
1024 if (IgnoreNegSides && curContact.side1 < 0)
1025 {
1026 if (++i >= count)
1027 break;
1028
1029 if (!GetCurContactGeom(i, ref curContact))
1030 break;
1031 }
1032 else
1033
1034 {
1035
1036 if (AvanormOverride)
1037 {
1038 if (curContact.depth > 0.3f)
1039 {
1040 if (dop1foot && (p1.Position.Z - curContact.pos.Z) > (p1.Size.Z - avCapRadius) * 0.5f)
1041 p1.IsColliding = true;
1042 if (dop2foot && (p2.Position.Z - curContact.pos.Z) > (p2.Size.Z - avCapRadius) * 0.5f)
1043 p2.IsColliding = true;
1044 curContact.normal.X = normoverride.X;
1045 curContact.normal.Y = normoverride.Y;
1046 curContact.normal.Z = normoverride.Z;
1047 }
1048
1049 else
1050 {
1051 if (dop1foot)
1052 {
1053 float sz = p1.Size.Z;
1054 Vector3 vtmp = p1.Position;
1055 float ppos = curContact.pos.Z - vtmp.Z + (sz - avCapRadius) * 0.5f;
1056 if (ppos > 0f)
1057 {
1058 if (!p1.Flying)
1059 {
1060 d.AABB aabb;
1061 d.GeomGetAABB(g2, out aabb);
1062 float tmp = vtmp.Z - sz * .25f;
1063
1064 if (aabb.MaxZ < tmp)
1065 {
1066 vtmp.X = curContact.pos.X - vtmp.X;
1067 vtmp.Y = curContact.pos.Y - vtmp.Y;
1068 vtmp.Z = -0.2f;
1069 vtmp.Normalize();
1070 curContact.normal.X = vtmp.X;
1071 curContact.normal.Y = vtmp.Y;
1072 curContact.normal.Z = vtmp.Z;
1073 }
1074 }
1075 }
1076 else
1077 p1.IsColliding = true;
1078
1079 }
1080
1081 if (dop2foot)
1082 {
1083 float sz = p2.Size.Z;
1084 Vector3 vtmp = p2.Position;
1085 float ppos = curContact.pos.Z - vtmp.Z + (sz - avCapRadius) * 0.5f;
1086 if (ppos > 0f)
1087 {
1088 if (!p2.Flying)
1089 {
1090 d.AABB aabb;
1091 d.GeomGetAABB(g1, out aabb);
1092 float tmp = vtmp.Z - sz * .25f;
1093
1094 if (aabb.MaxZ < tmp)
1095 {
1096 vtmp.X = curContact.pos.X - vtmp.X;
1097 vtmp.Y = curContact.pos.Y - vtmp.Y;
1098 vtmp.Z = -0.2f;
1099 vtmp.Normalize();
1100 curContact.normal.X = vtmp.X;
1101 curContact.normal.Y = vtmp.Y;
1102 curContact.normal.Z = vtmp.Z;
1103 }
1104 }
1105 }
1106 else
1107 p2.IsColliding = true;
1108
1109 }
1110 }
1111 }
1112
1113 Joint = CreateContacJoint(ref curContact, mu, bounce, cfm, erpscale, dscale);
1114 d.JointAttach(Joint, b1, b2);
1115
1116 if (++m_global_contactcount >= maxContactsbeforedeath)
1117 break;
1118
1119 if (++i >= count)
1120 break;
1121
1122 if (!GetCurContactGeom(i, ref curContact))
1123 break;
1124
1125 if (curContact.depth > maxDepthContact.PenetrationDepth)
1126 {
1127 maxDepthContact.Position.X = curContact.pos.X;
1128 maxDepthContact.Position.Y = curContact.pos.Y;
1129 maxDepthContact.Position.Z = curContact.pos.Z;
1130 maxDepthContact.SurfaceNormal.X = curContact.normal.X;
1131 maxDepthContact.SurfaceNormal.Y = curContact.normal.Y;
1132 maxDepthContact.SurfaceNormal.Z = curContact.normal.Z;
1133 maxDepthContact.PenetrationDepth = curContact.depth;
1134 }
1135 }
1136 }
1137
1138 collision_accounting_events(p1, p2, maxDepthContact);
1139
1140/*
1141 if (notskipedcount > geomContactPointsStartthrottle)
1142 {
1143 // If there are more then 3 contact points, it's likely
1144 // that we've got a pile of objects, so ...
1145 // We don't want to send out hundreds of terse updates over and over again
1146 // so lets throttle them and send them again after it's somewhat sorted out.
1147 this needs checking so out for now
1148 if (b1 != IntPtr.Zero)
1149 p1.ThrottleUpdates = true;
1150 if (b2 != IntPtr.Zero)
1151 p2.ThrottleUpdates = true;
1152
1153 }
1154 */
1155 }
1156
1157 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1158 {
1159
1160 OdeCharacter cc1;
1161 OdePrim cp1;
1162 OdeCharacter cc2;
1163 OdePrim cp2;
1164
1165 uint obj2LocalID = 0;
1166 bool p1events = p1.SubscribedEvents();
1167 bool p2events = p2.SubscribedEvents();
1168
1169 if (p1.IsVolumeDtc)
1170 p2events = false;
1171 if (p2.IsVolumeDtc)
1172 p1events = false;
1173
1174 if (!(p2events || p1events))
1175 return;
1176
1177 if (p1events)
1178 AddCollisionEventReporting(p1);
1179
1180 if (p2events)
1181 AddCollisionEventReporting(p2);
1182
1183 Vector3 vel = Vector3.Zero;
1184 if (p2 != null && p2.IsPhysical)
1185 vel = p2.Velocity;
1186
1187 if (p1 != null && p1.IsPhysical)
1188 vel -= p1.Velocity;
1189
1190 contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal);
1191
1192 switch ((ActorTypes)p1.PhysicsActorType)
1193 {
1194 case ActorTypes.Agent:
1195 cc1 = (OdeCharacter)p1;
1196 switch ((ActorTypes)p2.PhysicsActorType)
1197 {
1198 case ActorTypes.Agent:
1199 cc2 = (OdeCharacter)p2;
1200 obj2LocalID = cc2.m_localID;
1201 if (p2events)
1202 cc2.AddCollisionEvent(cc1.m_localID, contact);
1203 break;
1204
1205 case ActorTypes.Prim:
1206 if (p2 is OdePrim)
1207 {
1208 cp2 = (OdePrim)p2;
1209 obj2LocalID = cp2.m_localID;
1210 if (p2events)
1211 cp2.AddCollisionEvent(cc1.m_localID, contact);
1212 }
1213 break;
1214
1215 case ActorTypes.Ground:
1216 case ActorTypes.Unknown:
1217 default:
1218 obj2LocalID = 0;
1219 break;
1220 }
1221 if (p1events)
1222 {
1223 contact.SurfaceNormal = -contact.SurfaceNormal;
1224 cc1.AddCollisionEvent(obj2LocalID, contact);
1225 }
1226 break;
1227
1228 case ActorTypes.Prim:
1229
1230 if (p1 is OdePrim)
1231 {
1232 cp1 = (OdePrim)p1;
1233
1234 // obj1LocalID = cp2.m_localID;
1235 switch ((ActorTypes)p2.PhysicsActorType)
1236 {
1237 case ActorTypes.Agent:
1238 if (p2 is OdeCharacter)
1239 {
1240 cc2 = (OdeCharacter)p2;
1241 obj2LocalID = cc2.m_localID;
1242 if (p2events)
1243 cc2.AddCollisionEvent(cp1.m_localID, contact);
1244 }
1245 break;
1246 case ActorTypes.Prim:
1247
1248 if (p2 is OdePrim)
1249 {
1250 cp2 = (OdePrim)p2;
1251 obj2LocalID = cp2.m_localID;
1252 if (p2events)
1253 cp2.AddCollisionEvent(cp1.m_localID, contact);
1254 }
1255 break;
1256
1257 case ActorTypes.Ground:
1258 case ActorTypes.Unknown:
1259 default:
1260 obj2LocalID = 0;
1261 break;
1262 }
1263 if (p1events)
1264 {
1265 contact.SurfaceNormal = -contact.SurfaceNormal;
1266 cp1.AddCollisionEvent(obj2LocalID, contact);
1267 }
1268 }
1269 break;
1270 case ActorTypes.Ground:
1271 case ActorTypes.Unknown:
1272 default:
1273 switch ((ActorTypes)p2.PhysicsActorType)
1274 {
1275 case ActorTypes.Agent:
1276 if (p2 is OdeCharacter)
1277 {
1278 cc2 = (OdeCharacter)p2;
1279 obj2LocalID = cc2.m_localID;
1280 if (p2events)
1281 cc2.AddCollisionEvent(0, contact);
1282 }
1283 break;
1284 case ActorTypes.Prim:
1285 if (p2 is OdePrim)
1286 {
1287 cp2 = (OdePrim)p2;
1288 obj2LocalID = cp2.m_localID;
1289 if (p2events)
1290 cp2.AddCollisionEvent(0, contact);
1291 }
1292 break;
1293 }
1294 break;
1295 }
1296 }
1297
1298 /// <summary>
1299 /// This is our collision testing routine in ODE
1300 /// </summary>
1301 /// <param name="timeStep"></param>
1302 private void collision_optimized()
1303 {
1304 lock (_characters)
1305 {
1306 try
1307 {
1308 foreach (OdeCharacter chr in _characters)
1309 {
1310 if (chr == null || chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1311 continue;
1312
1313 chr.IsColliding = false;
1314 // chr.CollidingGround = false; not done here
1315 chr.CollidingObj = false;
1316 // do colisions with static space
1317 d.SpaceCollide2(StaticSpace, chr.Shell, IntPtr.Zero, nearCallback);
1318 }
1319 }
1320 catch (AccessViolationException)
1321 {
1322 m_log.Warn("[PHYSICS]: Unable to collide Character to static space");
1323 }
1324
1325 }
1326
1327 lock (_activeprims)
1328 {
1329 foreach (OdePrim aprim in _activeprims)
1330 {
1331 aprim.CollisionScore = 0;
1332 aprim.IsColliding = false;
1333 }
1334 }
1335
1336 // collide active prims with static enviroment
1337 lock (_activegroups)
1338 {
1339 try
1340 {
1341 foreach (OdePrim prm in _activegroups)
1342 {
1343 if (d.BodyIsEnabled(prm.Body) && !prm.m_outbounds)
1344 d.SpaceCollide2(StaticSpace, prm.collide_geom, IntPtr.Zero, nearCallback);
1345 }
1346 }
1347 catch (AccessViolationException)
1348 {
1349 m_log.Warn("[PHYSICS]: Unable to collide Active prim to static space");
1350 }
1351 }
1352 // finally colide active things amoung them
1353 try
1354 {
1355 d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback);
1356 }
1357 catch (AccessViolationException)
1358 {
1359 m_log.Warn("[PHYSICS]: Unable to collide in Active space");
1360 }
1361// _perloopContact.Clear();
1362 }
1363
1364 #endregion
1365 /// <summary>
1366 /// Add actor to the list that should receive collision events in the simulate loop.
1367 /// </summary>
1368 /// <param name="obj"></param>
1369 public void AddCollisionEventReporting(PhysicsActor obj)
1370 {
1371 if (!_collisionEventPrim.Contains(obj))
1372 _collisionEventPrim.Add(obj);
1373 }
1374
1375 /// <summary>
1376 /// Remove actor from the list that should receive collision events in the simulate loop.
1377 /// </summary>
1378 /// <param name="obj"></param>
1379 public void RemoveCollisionEventReporting(PhysicsActor obj)
1380 {
1381 if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj))
1382 _collisionEventPrimRemove.Add(obj);
1383 }
1384
1385
1386 #region Add/Remove Entities
1387
1388 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1389 {
1390 Vector3 pos;
1391 pos.X = position.X;
1392 pos.Y = position.Y;
1393 pos.Z = position.Z;
1394 OdeCharacter newAv = new OdeCharacter(avName, this, pos, size, avPIDD, avPIDP, avCapRadius, avDensity, avMovementDivisorWalk, avMovementDivisorRun);
1395 newAv.Flying = isFlying;
1396 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1397
1398 return newAv;
1399 }
1400
1401 public void AddCharacter(OdeCharacter chr)
1402 {
1403 lock (_characters)
1404 {
1405 if (!_characters.Contains(chr))
1406 {
1407 _characters.Add(chr);
1408 if (chr.bad)
1409 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1410 }
1411 }
1412 }
1413
1414 public void RemoveCharacter(OdeCharacter chr)
1415 {
1416 lock (_characters)
1417 {
1418 if (_characters.Contains(chr))
1419 {
1420 _characters.Remove(chr);
1421 }
1422 }
1423 }
1424
1425 public void BadCharacter(OdeCharacter chr)
1426 {
1427 lock (_badCharacter)
1428 {
1429 if (!_badCharacter.Contains(chr))
1430 _badCharacter.Add(chr);
1431 }
1432 }
1433
1434 public override void RemoveAvatar(PhysicsActor actor)
1435 {
1436 //m_log.Debug("[PHYSICS]:ODELOCK");
1437 ((OdeCharacter) actor).Destroy();
1438 }
1439
1440 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1441 PrimitiveBaseShape pbs, bool isphysical, uint localID)
1442 {
1443 Vector3 pos = position;
1444 Vector3 siz = size;
1445 Quaternion rot = rotation;
1446
1447 OdePrim newPrim;
1448 lock (OdeLock)
1449 {
1450 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical,false,0,localID);
1451
1452 lock (_prims)
1453 _prims.Add(newPrim);
1454 }
1455 return newPrim;
1456 }
1457
1458 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1459 PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, uint localID)
1460 {
1461 Vector3 pos = position;
1462 Vector3 siz = size;
1463 Quaternion rot = rotation;
1464
1465 OdePrim newPrim;
1466 lock (OdeLock)
1467 {
1468 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical, isPhantom, 0, localID);
1469
1470 lock (_prims)
1471 _prims.Add(newPrim);
1472 }
1473 return newPrim;
1474 }
1475
1476 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1477 PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID)
1478 {
1479 Vector3 pos = position;
1480 Vector3 siz = size;
1481 Quaternion rot = rotation;
1482
1483 OdePrim newPrim;
1484 lock (OdeLock)
1485 {
1486 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical, isPhantom, shapeType, localID);
1487
1488 lock (_prims)
1489 _prims.Add(newPrim);
1490 }
1491 return newPrim;
1492 }
1493
1494 public void addActivePrim(OdePrim activatePrim)
1495 {
1496 // adds active prim..
1497 lock (_activeprims)
1498 {
1499 if (!_activeprims.Contains(activatePrim))
1500 _activeprims.Add(activatePrim);
1501 }
1502 }
1503
1504 public void addActiveGroups(OdePrim activatePrim)
1505 {
1506 lock (_activegroups)
1507 {
1508 if (!_activegroups.Contains(activatePrim))
1509 _activegroups.Add(activatePrim);
1510 }
1511 }
1512
1513 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1514 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid)
1515 {
1516 return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, localid);
1517 }
1518
1519
1520 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1521 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
1522 {
1523#if SPAM
1524 m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
1525#endif
1526
1527 return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
1528 }
1529
1530 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1531 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid)
1532 {
1533#if SPAM
1534 m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
1535#endif
1536
1537 return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid);
1538 }
1539
1540 public override float TimeDilation
1541 {
1542 get { return m_timeDilation; }
1543 }
1544
1545 public override bool SupportsNINJAJoints
1546 {
1547 get { return false; }
1548 }
1549
1550
1551 public void remActivePrim(OdePrim deactivatePrim)
1552 {
1553 lock (_activeprims)
1554 {
1555 _activeprims.Remove(deactivatePrim);
1556 }
1557 }
1558 public void remActiveGroup(OdePrim deactivatePrim)
1559 {
1560 lock (_activegroups)
1561 {
1562 _activegroups.Remove(deactivatePrim);
1563 }
1564 }
1565
1566 public override void RemovePrim(PhysicsActor prim)
1567 {
1568 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
1569 // removed in the next physics simulate pass.
1570 if (prim is OdePrim)
1571 {
1572// lock (OdeLock)
1573 {
1574
1575 OdePrim p = (OdePrim)prim;
1576 p.setPrimForRemoval();
1577 }
1578 }
1579 }
1580 /// <summary>
1581 /// This is called from within simulate but outside the locked portion
1582 /// We need to do our own locking here
1583 /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in
1584 /// Simulate() -- justincc).
1585 ///
1586 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
1587 ///
1588 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
1589 /// that the space was using.
1590 /// </summary>
1591 /// <param name="prim"></param>
1592 public void RemovePrimThreadLocked(OdePrim prim)
1593 {
1594 //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
1595 lock (prim)
1596 {
1597 RemoveCollisionEventReporting(prim);
1598 lock (_prims)
1599 _prims.Remove(prim);
1600 }
1601
1602 }
1603 #endregion
1604
1605 #region Space Separation Calculation
1606
1607 /// <summary>
1608 /// Called when a static prim moves or becomes static
1609 /// Places the prim in a space one the static sub-spaces grid
1610 /// </summary>
1611 /// <param name="geom">the pointer to the geom that moved</param>
1612 /// <param name="pos">the position that the geom moved to</param>
1613 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
1614 /// <returns>a pointer to the new space it's in</returns>
1615 public IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace)
1616 {
1617 // moves a prim into another static sub-space or from another space into a static sub-space
1618
1619 // Called ODEPrim so
1620 // it's already in locked space.
1621
1622 if (geom == IntPtr.Zero) // shouldn't happen
1623 return IntPtr.Zero;
1624
1625 // get the static sub-space for current position
1626 IntPtr newspace = calculateSpaceForGeom(pos);
1627
1628 if (newspace == currentspace) // if we are there all done
1629 return newspace;
1630
1631 // else remove it from its current space
1632 if (currentspace != IntPtr.Zero && d.SpaceQuery(currentspace, geom))
1633 {
1634 if (d.GeomIsSpace(currentspace))
1635 {
1636 waitForSpaceUnlock(currentspace);
1637 d.SpaceRemove(currentspace, geom);
1638
1639 if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
1640 {
1641 d.SpaceDestroy(currentspace);
1642 }
1643 }
1644 else
1645 {
1646 m_log.Info("[Physics]: Invalid or empty Space passed to 'MoveGeomToStaticSpace':" + currentspace +
1647 " Geom:" + geom);
1648 }
1649 }
1650 else // odd currentspace is null or doesn't contain the geom? lets try the geom ideia of current space
1651 {
1652 currentspace = d.GeomGetSpace(geom);
1653 if (currentspace != IntPtr.Zero)
1654 {
1655 if (d.GeomIsSpace(currentspace))
1656 {
1657 waitForSpaceUnlock(currentspace);
1658 d.SpaceRemove(currentspace, geom);
1659
1660 if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0)
1661 {
1662 d.SpaceDestroy(currentspace);
1663 }
1664
1665 }
1666 }
1667 }
1668
1669 // put the geom in the newspace
1670 waitForSpaceUnlock(newspace);
1671 d.SpaceAdd(newspace, geom);
1672
1673 // let caller know this newspace
1674 return newspace;
1675 }
1676
1677 /// <summary>
1678 /// Calculates the space the prim should be in by its position
1679 /// </summary>
1680 /// <param name="pos"></param>
1681 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
1682 public IntPtr calculateSpaceForGeom(Vector3 pos)
1683 {
1684 int x, y;
1685
1686 if (pos.X < 0)
1687 return staticPrimspaceOffRegion[0];
1688
1689 if (pos.Y < 0)
1690 return staticPrimspaceOffRegion[2];
1691
1692 x = (int)(pos.X * spacesPerMeter);
1693 if (x > spaceGridMaxX)
1694 return staticPrimspaceOffRegion[1];
1695
1696 y = (int)(pos.Y * spacesPerMeter);
1697 if (y > spaceGridMaxY)
1698 return staticPrimspaceOffRegion[3];
1699
1700 return staticPrimspace[x, y];
1701 }
1702
1703 #endregion
1704
1705 /// <summary>
1706 /// Routine to figure out if we need to mesh this prim with our mesher
1707 /// </summary>
1708 /// <param name="pbs"></param>
1709 /// <returns></returns>
1710 public bool needsMeshing(PrimitiveBaseShape pbs)
1711 {
1712 // check sculpts or meshs
1713 if (pbs.SculptEntry)
1714 {
1715 if (meshSculptedPrim)
1716 return true;
1717
1718 if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs
1719 return true;
1720
1721 return false;
1722 }
1723
1724 if (forceSimplePrimMeshing)
1725 return true;
1726
1727 // 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
1728
1729 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
1730 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
1731 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
1732 {
1733
1734 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
1735 && pbs.ProfileHollow == 0
1736 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
1737 && pbs.PathBegin == 0 && pbs.PathEnd == 0
1738 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
1739 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
1740 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
1741 {
1742#if SPAM
1743 m_log.Warn("NonMesh");
1744#endif
1745 return false;
1746 }
1747 }
1748
1749 // following code doesn't give meshs to boxes and spheres ever
1750 // and it's odd.. so for now just return true if asked to force meshs
1751 // hopefully mesher will fail if doesn't suport so things still get basic boxes
1752
1753 int iPropertiesNotSupportedDefault = 0;
1754
1755 if (pbs.ProfileHollow != 0)
1756 iPropertiesNotSupportedDefault++;
1757
1758 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
1759 iPropertiesNotSupportedDefault++;
1760
1761 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
1762 iPropertiesNotSupportedDefault++;
1763
1764 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
1765 iPropertiesNotSupportedDefault++;
1766
1767 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
1768 iPropertiesNotSupportedDefault++;
1769
1770 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
1771 iPropertiesNotSupportedDefault++;
1772
1773 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
1774 iPropertiesNotSupportedDefault++;
1775
1776 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))
1777 iPropertiesNotSupportedDefault++;
1778
1779 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
1780 iPropertiesNotSupportedDefault++;
1781
1782 // test for torus
1783 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
1784 {
1785 if (pbs.PathCurve == (byte)Extrusion.Curve1)
1786 {
1787 iPropertiesNotSupportedDefault++;
1788 }
1789 }
1790 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
1791 {
1792 if (pbs.PathCurve == (byte)Extrusion.Straight)
1793 {
1794 iPropertiesNotSupportedDefault++;
1795 }
1796
1797 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
1798 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
1799 {
1800 iPropertiesNotSupportedDefault++;
1801 }
1802 }
1803 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
1804 {
1805 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
1806 {
1807 iPropertiesNotSupportedDefault++;
1808 }
1809 }
1810 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
1811 {
1812 if (pbs.PathCurve == (byte)Extrusion.Straight)
1813 {
1814 iPropertiesNotSupportedDefault++;
1815 }
1816 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
1817 {
1818 iPropertiesNotSupportedDefault++;
1819 }
1820 }
1821
1822 if (iPropertiesNotSupportedDefault == 0)
1823 {
1824#if SPAM
1825 m_log.Warn("NonMesh");
1826#endif
1827 return false;
1828 }
1829#if SPAM
1830 m_log.Debug("Mesh");
1831#endif
1832 return true;
1833 }
1834
1835 /// <summary>
1836 /// Called to queue a change to a actor
1837 /// to use in place of old taint mechanism so changes do have a time sequence
1838 /// </summary>
1839
1840 public void AddChange(PhysicsActor actor, changes what, Object arg)
1841 {
1842 ODEchangeitem item = new ODEchangeitem();
1843 item.actor = actor;
1844 item.what = what;
1845 item.arg = arg;
1846 ChangesQueue.Enqueue(item);
1847 }
1848
1849 /// <summary>
1850 /// Called after our prim properties are set Scale, position etc.
1851 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
1852 /// This assures us that we have no race conditions
1853 /// </summary>
1854 /// <param name="prim"></param>
1855 public override void AddPhysicsActorTaint(PhysicsActor prim)
1856 {
1857 }
1858
1859 /// <summary>
1860 /// This is our main simulate loop
1861 /// It's thread locked by a Mutex in the scene.
1862 /// It holds Collisions, it instructs ODE to step through the physical reactions
1863 /// It moves the objects around in memory
1864 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
1865 /// </summary>
1866 /// <param name="timeStep"></param>
1867 /// <returns></returns>
1868 public override float Simulate(float timeStep)
1869 {
1870
1871 DateTime now = DateTime.UtcNow;
1872 TimeSpan SinceLastFrame = now - m_lastframe;
1873 m_lastframe = now;
1874 timeStep = (float)SinceLastFrame.TotalSeconds;
1875
1876 // acumulate time so we can reduce error
1877 step_time += timeStep;
1878
1879 if (step_time < HalfOdeStep)
1880 return 0;
1881
1882 if (framecount < 0)
1883 framecount = 0;
1884
1885 framecount++;
1886
1887 int curphysiteractions;
1888
1889 // if in trouble reduce step resolution
1890 if (step_time >= m_SkipFramesAtms)
1891 curphysiteractions = m_physicsiterations / 2;
1892 else
1893 curphysiteractions = m_physicsiterations;
1894
1895 int nodeframes = 0;
1896
1897// checkThread();
1898
1899 lock (SimulationLock)
1900 lock(OdeLock)
1901 {
1902 if (world == IntPtr.Zero)
1903 return 0;
1904
1905 // adjust number of iterations per step
1906
1907// try
1908// {
1909 d.WorldSetQuickStepNumIterations(world, curphysiteractions);
1910/* }
1911 catch (StackOverflowException)
1912 {
1913 m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
1914// ode.drelease(world);
1915 base.TriggerPhysicsBasedRestart();
1916 }
1917*/
1918 while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever
1919 {
1920 try
1921 {
1922 // clear pointer/counter to contacts to pass into joints
1923 m_global_contactcount = 0;
1924
1925 ODEchangeitem item;
1926
1927 if(ChangesQueue.Count >0)
1928 {
1929 int ttmpstart = Util.EnvironmentTickCount();
1930 int ttmp;
1931
1932 while(ChangesQueue.Dequeue(out item))
1933 {
1934 if (item.actor != null)
1935 {
1936 try
1937 {
1938 if (item.actor is OdeCharacter)
1939 ((OdeCharacter)item.actor).DoAChange(item.what, item.arg);
1940 else if (((OdePrim)item.actor).DoAChange(item.what, item.arg))
1941 RemovePrimThreadLocked((OdePrim)item.actor);
1942 }
1943 catch
1944 {
1945 m_log.Warn("[PHYSICS]: doChange failed for a actor");
1946 };
1947 }
1948 ttmp = Util.EnvironmentTickCountSubtract(ttmpstart);
1949 if (ttmp > 20)
1950 break;
1951 }
1952 }
1953
1954 // Move characters
1955 lock (_characters)
1956 {
1957 List<OdeCharacter> defects = new List<OdeCharacter>();
1958 foreach (OdeCharacter actor in _characters)
1959 {
1960 if (actor != null)
1961 actor.Move(ODE_STEPSIZE, defects);
1962 }
1963 if (defects.Count != 0)
1964 {
1965 foreach (OdeCharacter defect in defects)
1966 {
1967 RemoveCharacter(defect);
1968 }
1969 defects.Clear();
1970 }
1971 }
1972
1973 // Move other active objects
1974 lock (_activegroups)
1975 {
1976 foreach (OdePrim aprim in _activegroups)
1977 {
1978 aprim.Move();
1979 }
1980 }
1981
1982 //if ((framecount % m_randomizeWater) == 0)
1983 // randomizeWater(waterlevel);
1984
1985 m_rayCastManager.ProcessQueuedRequests();
1986
1987 collision_optimized();
1988
1989 foreach (PhysicsActor obj in _collisionEventPrim)
1990 {
1991 if (obj == null)
1992 continue;
1993
1994 switch ((ActorTypes)obj.PhysicsActorType)
1995 {
1996 case ActorTypes.Agent:
1997 OdeCharacter cobj = (OdeCharacter)obj;
1998 cobj.AddCollisionFrameTime((int)(odetimestepMS));
1999 cobj.SendCollisions();
2000 break;
2001
2002 case ActorTypes.Prim:
2003 OdePrim pobj = (OdePrim)obj;
2004 if (pobj.Body == IntPtr.Zero || (d.BodyIsEnabled(pobj.Body) && !pobj.m_outbounds))
2005 {
2006 pobj.AddCollisionFrameTime((int)(odetimestepMS));
2007 pobj.SendCollisions();
2008 }
2009 break;
2010 }
2011 }
2012
2013 foreach (PhysicsActor obj in _collisionEventPrimRemove)
2014 _collisionEventPrim.Remove(obj);
2015
2016 _collisionEventPrimRemove.Clear();
2017
2018 // do a ode simulation step
2019 d.WorldQuickStep(world, ODE_STEPSIZE);
2020 d.JointGroupEmpty(contactgroup);
2021
2022 // update managed ideia of physical data and do updates to core
2023 /*
2024 lock (_characters)
2025 {
2026 foreach (OdeCharacter actor in _characters)
2027 {
2028 if (actor != null)
2029 {
2030 if (actor.bad)
2031 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
2032
2033 actor.UpdatePositionAndVelocity();
2034 }
2035 }
2036 }
2037 */
2038
2039 lock (_activegroups)
2040 {
2041 {
2042 foreach (OdePrim actor in _activegroups)
2043 {
2044 if (actor.IsPhysical)
2045 {
2046 actor.UpdatePositionAndVelocity();
2047 }
2048 }
2049 }
2050 }
2051 }
2052 catch (Exception e)
2053 {
2054 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
2055// ode.dunlock(world);
2056 }
2057
2058
2059 step_time -= ODE_STEPSIZE;
2060 nodeframes++;
2061 }
2062
2063 lock (_badCharacter)
2064 {
2065 if (_badCharacter.Count > 0)
2066 {
2067 foreach (OdeCharacter chr in _badCharacter)
2068 {
2069 RemoveCharacter(chr);
2070 }
2071
2072 _badCharacter.Clear();
2073 }
2074 }
2075/*
2076 int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
2077 int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
2078 int ntopgeoms = d.SpaceGetNumGeoms(TopSpace);
2079 int nbodies = d.NTotalBodies;
2080 int ngeoms = d.NTotalGeoms;
2081*/
2082 // Finished with all sim stepping. If requested, dump world state to file for debugging.
2083 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
2084 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
2085 if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
2086 {
2087 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
2088 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
2089
2090 if (physics_logging_append_existing_logfile)
2091 {
2092 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
2093 TextWriter fwriter = File.AppendText(fname);
2094 fwriter.WriteLine(header);
2095 fwriter.Close();
2096 }
2097
2098 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
2099 }
2100
2101 // think time dilation as to do with dinamic step size that we dont' have
2102 // even so tell something to world
2103 if (nodeframes < 10) // we did the requested loops
2104 m_timeDilation = 1.0f;
2105 else if (step_time > 0)
2106 {
2107 m_timeDilation = timeStep / step_time;
2108 if (m_timeDilation > 1)
2109 m_timeDilation = 1;
2110 if (step_time > m_SkipFramesAtms)
2111 step_time = 0;
2112 }
2113 }
2114
2115// return nodeframes * ODE_STEPSIZE; // return real simulated time
2116 return 1000 * nodeframes; // return steps for now * 1000 to keep core happy
2117 }
2118
2119 /// <summary>
2120 public override void GetResults()
2121 {
2122 }
2123
2124 public override bool IsThreaded
2125 {
2126 // for now we won't be multithreaded
2127 get { return (false); }
2128 }
2129
2130 public float GetTerrainHeightAtXY(float x, float y)
2131 {
2132
2133
2134 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
2135 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
2136
2137
2138 IntPtr heightFieldGeom = IntPtr.Zero;
2139
2140 // get region map
2141 if (!RegionTerrain.TryGetValue(new Vector3(offsetX, offsetY, 0), out heightFieldGeom))
2142 return 0f;
2143
2144 if (heightFieldGeom == IntPtr.Zero)
2145 return 0f;
2146
2147 if (!TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
2148 return 0f;
2149
2150 // TerrainHeightField for ODE as offset 1m
2151 x += 1f - offsetX;
2152 y += 1f - offsetY;
2153
2154 // make position fit into array
2155 if (x < 0)
2156 x = 0;
2157 if (y < 0)
2158 y = 0;
2159
2160 // integer indexs
2161 int ix;
2162 int iy;
2163 // interpolators offset
2164 float dx;
2165 float dy;
2166
2167 int regsize = (int)Constants.RegionSize + 3; // map size see setterrain number of samples
2168
2169 if (OdeUbitLib)
2170 {
2171 if (x < regsize - 1)
2172 {
2173 ix = (int)x;
2174 dx = x - (float)ix;
2175 }
2176 else // out world use external height
2177 {
2178 ix = regsize - 2;
2179 dx = 0;
2180 }
2181 if (y < regsize - 1)
2182 {
2183 iy = (int)y;
2184 dy = y - (float)iy;
2185 }
2186 else
2187 {
2188 iy = regsize - 2;
2189 dy = 0;
2190 }
2191 }
2192
2193 else
2194 {
2195 // we still have square fixed size regions
2196 // also flip x and y because of how map is done for ODE fliped axis
2197 // so ix,iy,dx and dy are inter exchanged
2198 if (x < regsize - 1)
2199 {
2200 iy = (int)x;
2201 dy = x - (float)iy;
2202 }
2203 else // out world use external height
2204 {
2205 iy = regsize - 2;
2206 dy = 0;
2207 }
2208 if (y < regsize - 1)
2209 {
2210 ix = (int)y;
2211 dx = y - (float)ix;
2212 }
2213 else
2214 {
2215 ix = regsize - 2;
2216 dx = 0;
2217 }
2218 }
2219
2220 float h0;
2221 float h1;
2222 float h2;
2223
2224 iy *= regsize;
2225 iy += ix; // all indexes have iy + ix
2226
2227 float[] heights = TerrainHeightFieldHeights[heightFieldGeom];
2228 /*
2229 if ((dx + dy) <= 1.0f)
2230 {
2231 h0 = ((float)heights[iy]); // 0,0 vertice
2232 h1 = (((float)heights[iy + 1]) - h0) * dx; // 1,0 vertice minus 0,0
2233 h2 = (((float)heights[iy + regsize]) - h0) * dy; // 0,1 vertice minus 0,0
2234 }
2235 else
2236 {
2237 h0 = ((float)heights[iy + regsize + 1]); // 1,1 vertice
2238 h1 = (((float)heights[iy + 1]) - h0) * (1 - dy); // 1,1 vertice minus 1,0
2239 h2 = (((float)heights[iy + regsize]) - h0) * (1 - dx); // 1,1 vertice minus 0,1
2240 }
2241 */
2242 h0 = ((float)heights[iy]); // 0,0 vertice
2243
2244 if ((dy > dx))
2245 {
2246 iy += regsize;
2247 h2 = (float)heights[iy]; // 0,1 vertice
2248 h1 = (h2 - h0) * dy; // 0,1 vertice minus 0,0
2249 h2 = ((float)heights[iy + 1] - h2) * dx; // 1,1 vertice minus 0,1
2250 }
2251 else
2252 {
2253 iy++;
2254 h2 = (float)heights[iy]; // vertice 1,0
2255 h1 = (h2 - h0) * dx; // 1,0 vertice minus 0,0
2256 h2 = (((float)heights[iy + regsize]) - h2) * dy; // 1,1 vertice minus 1,0
2257 }
2258
2259 return h0 + h1 + h2;
2260 }
2261
2262
2263 public override void SetTerrain(float[] heightMap)
2264 {
2265 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
2266 {
2267 if (m_parentScene is OdeScene)
2268 {
2269 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
2270 }
2271 }
2272 else
2273 {
2274 SetTerrain(heightMap, m_worldOffset);
2275 }
2276 }
2277
2278 public override void CombineTerrain(float[] heightMap, Vector3 pOffset)
2279 {
2280 SetTerrain(heightMap, pOffset);
2281 }
2282
2283 public void SetTerrain(float[] heightMap, Vector3 pOffset)
2284 {
2285 if (OdeUbitLib)
2286 UbitSetTerrain(heightMap, pOffset);
2287 else
2288 OriSetTerrain(heightMap, pOffset);
2289 }
2290
2291 public void OriSetTerrain(float[] heightMap, Vector3 pOffset)
2292 {
2293 // assumes 1m size grid and constante size square regions
2294 // needs to know about sims around in future
2295
2296 float[] _heightmap;
2297
2298 uint heightmapWidth = Constants.RegionSize + 2;
2299 uint heightmapHeight = Constants.RegionSize + 2;
2300
2301 uint heightmapWidthSamples = heightmapWidth + 1;
2302 uint heightmapHeightSamples = heightmapHeight + 1;
2303
2304 _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
2305
2306 const float scale = 1.0f;
2307 const float offset = 0.0f;
2308 const float thickness = 10f;
2309 const int wrap = 0;
2310
2311 uint regionsize = Constants.RegionSize;
2312
2313 float hfmin = float.MaxValue;
2314 float hfmax = float.MinValue;
2315 float val;
2316 uint xx;
2317 uint yy;
2318
2319 uint maxXXYY = regionsize - 1;
2320 // flipping map adding one margin all around so things don't fall in edges
2321
2322 uint xt = 0;
2323 xx = 0;
2324
2325 for (uint x = 0; x < heightmapWidthSamples; x++)
2326 {
2327 if (x > 1 && xx < maxXXYY)
2328 xx++;
2329 yy = 0;
2330 for (uint y = 0; y < heightmapHeightSamples; y++)
2331 {
2332 if (y > 1 && y < maxXXYY)
2333 yy += regionsize;
2334
2335 val = heightMap[yy + xx];
2336 if (val < 0.0f)
2337 val = 0.0f; // no neg terrain as in chode
2338 _heightmap[xt + y] = val;
2339
2340 if (hfmin > val)
2341 hfmin = val;
2342 if (hfmax < val)
2343 hfmax = val;
2344 }
2345 xt += heightmapHeightSamples;
2346 }
2347 lock (OdeLock)
2348 {
2349 IntPtr GroundGeom = IntPtr.Zero;
2350 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
2351 {
2352 RegionTerrain.Remove(pOffset);
2353 if (GroundGeom != IntPtr.Zero)
2354 {
2355 d.GeomDestroy(GroundGeom);
2356
2357 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
2358 {
2359 TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
2360 TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
2361 TerrainHeightFieldHeights.Remove(GroundGeom);
2362 }
2363 }
2364 }
2365 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
2366
2367 GCHandle _heightmaphandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
2368
2369 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmaphandler.AddrOfPinnedObject(), 0, heightmapWidth , heightmapHeight,
2370 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
2371 offset, thickness, wrap);
2372
2373 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
2374 GroundGeom = d.CreateHeightfield(StaticSpace, HeightmapData, 1);
2375 if (GroundGeom != IntPtr.Zero)
2376 {
2377 d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
2378 d.GeomSetCollideBits(GroundGeom, 0);
2379
2380 }
2381 geom_name_map[GroundGeom] = "Terrain";
2382
2383 d.Matrix3 R = new d.Matrix3();
2384
2385 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
2386 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
2387
2388
2389 q1 = q1 * q2;
2390
2391 Vector3 v3;
2392 float angle;
2393 q1.GetAxisAngle(out v3, out angle);
2394
2395 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
2396 d.GeomSetRotation(GroundGeom, ref R);
2397 d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0);
2398 RegionTerrain.Add(pOffset, GroundGeom);
2399 TerrainHeightFieldHeights.Add(GroundGeom, _heightmap);
2400 TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler);
2401 }
2402 }
2403
2404 public void UbitSetTerrain(float[] heightMap, Vector3 pOffset)
2405 {
2406 // assumes 1m size grid and constante size square regions
2407 // needs to know about sims around in future
2408
2409 float[] _heightmap;
2410
2411 uint heightmapWidth = Constants.RegionSize + 2;
2412 uint heightmapHeight = Constants.RegionSize + 2;
2413
2414 uint heightmapWidthSamples = heightmapWidth + 1;
2415 uint heightmapHeightSamples = heightmapHeight + 1;
2416
2417 _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
2418
2419
2420 uint regionsize = Constants.RegionSize;
2421
2422 float hfmin = float.MaxValue;
2423// float hfmax = float.MinValue;
2424 float val;
2425
2426
2427 uint maxXXYY = regionsize - 1;
2428 // adding one margin all around so things don't fall in edges
2429
2430 uint xx;
2431 uint yy = 0;
2432 uint yt = 0;
2433
2434 for (uint y = 0; y < heightmapHeightSamples; y++)
2435 {
2436 if (y > 1 && y < maxXXYY)
2437 yy += regionsize;
2438 xx = 0;
2439 for (uint x = 0; x < heightmapWidthSamples; x++)
2440 {
2441 if (x > 1 && x < maxXXYY)
2442 xx++;
2443
2444 val = heightMap[yy + xx];
2445 if (val < 0.0f)
2446 val = 0.0f; // no neg terrain as in chode
2447 _heightmap[yt + x] = val;
2448
2449 if (hfmin > val)
2450 hfmin = val;
2451// if (hfmax < val)
2452// hfmax = val;
2453 }
2454 yt += heightmapWidthSamples;
2455 }
2456 lock (OdeLock)
2457 {
2458 IntPtr GroundGeom = IntPtr.Zero;
2459 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
2460 {
2461 RegionTerrain.Remove(pOffset);
2462 if (GroundGeom != IntPtr.Zero)
2463 {
2464 d.GeomDestroy(GroundGeom);
2465
2466 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
2467 {
2468 if (TerrainHeightFieldHeightsHandlers[GroundGeom].IsAllocated)
2469 TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
2470 TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
2471 TerrainHeightFieldHeights.Remove(GroundGeom);
2472 }
2473 }
2474 }
2475 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
2476
2477 const int wrap = 0;
2478 float thickness = hfmin;
2479 if (thickness < 0)
2480 thickness = 1;
2481
2482 GCHandle _heightmaphandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned);
2483
2484 d.GeomUbitTerrainDataBuild(HeightmapData, _heightmaphandler.AddrOfPinnedObject(), 0, 1.0f,
2485 (int)heightmapWidthSamples, (int)heightmapHeightSamples,
2486 thickness, wrap);
2487
2488// d.GeomUbitTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
2489 GroundGeom = d.CreateUbitTerrain(StaticSpace, HeightmapData, 1);
2490 if (GroundGeom != IntPtr.Zero)
2491 {
2492 d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
2493 d.GeomSetCollideBits(GroundGeom, 0);
2494
2495 }
2496 geom_name_map[GroundGeom] = "Terrain";
2497
2498 d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0);
2499 RegionTerrain.Add(pOffset, GroundGeom);
2500 TerrainHeightFieldHeights.Add(GroundGeom, _heightmap);
2501 TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler);
2502 }
2503 }
2504
2505
2506 public override void DeleteTerrain()
2507 {
2508 }
2509
2510 public float GetWaterLevel()
2511 {
2512 return waterlevel;
2513 }
2514
2515 public override bool SupportsCombining()
2516 {
2517 return true;
2518 }
2519/*
2520 public override void UnCombine(PhysicsScene pScene)
2521 {
2522 IntPtr localGround = IntPtr.Zero;
2523// float[] localHeightfield;
2524 bool proceed = false;
2525 List<IntPtr> geomDestroyList = new List<IntPtr>();
2526
2527 lock (OdeLock)
2528 {
2529 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
2530 {
2531 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
2532 {
2533 if (geom == localGround)
2534 {
2535// localHeightfield = TerrainHeightFieldHeights[geom];
2536 proceed = true;
2537 }
2538 else
2539 {
2540 geomDestroyList.Add(geom);
2541 }
2542 }
2543
2544 if (proceed)
2545 {
2546 m_worldOffset = Vector3.Zero;
2547 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
2548 m_parentScene = null;
2549
2550 foreach (IntPtr g in geomDestroyList)
2551 {
2552 // removingHeightField needs to be done or the garbage collector will
2553 // collect the terrain data before we tell ODE to destroy it causing
2554 // memory corruption
2555 if (TerrainHeightFieldHeights.ContainsKey(g))
2556 {
2557// float[] removingHeightField = TerrainHeightFieldHeights[g];
2558 TerrainHeightFieldHeights.Remove(g);
2559
2560 if (RegionTerrain.ContainsKey(g))
2561 {
2562 RegionTerrain.Remove(g);
2563 }
2564
2565 d.GeomDestroy(g);
2566 //removingHeightField = new float[0];
2567 }
2568 }
2569
2570 }
2571 else
2572 {
2573 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
2574 }
2575 }
2576 }
2577 }
2578*/
2579 public override void SetWaterLevel(float baseheight)
2580 {
2581 waterlevel = baseheight;
2582 randomizeWater(waterlevel);
2583 }
2584
2585 public void randomizeWater(float baseheight)
2586 {
2587 const uint heightmapWidth = Constants.RegionSize + 2;
2588 const uint heightmapHeight = Constants.RegionSize + 2;
2589 const uint heightmapWidthSamples = heightmapWidth + 1;
2590 const uint heightmapHeightSamples = heightmapHeight + 1;
2591
2592 const float scale = 1.0f;
2593 const float offset = 0.0f;
2594 const int wrap = 0;
2595
2596 float[] _watermap = new float[heightmapWidthSamples * heightmapWidthSamples];
2597
2598 float maxheigh = float.MinValue;
2599 float minheigh = float.MaxValue;
2600 float val;
2601 for (int i = 0; i < (heightmapWidthSamples * heightmapHeightSamples); i++)
2602 {
2603
2604 val = (baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f);
2605 _watermap[i] = val;
2606 if (maxheigh < val)
2607 maxheigh = val;
2608 if (minheigh > val)
2609 minheigh = val;
2610 }
2611
2612 float thickness = minheigh;
2613
2614 lock (OdeLock)
2615 {
2616 if (WaterGeom != IntPtr.Zero)
2617 {
2618 d.GeomDestroy(WaterGeom);
2619 d.GeomHeightfieldDataDestroy(WaterHeightmapData);
2620 WaterGeom = IntPtr.Zero;
2621 WaterHeightmapData = IntPtr.Zero;
2622 if(WaterMapHandler.IsAllocated)
2623 WaterMapHandler.Free();
2624 }
2625
2626 WaterHeightmapData = d.GeomHeightfieldDataCreate();
2627
2628 WaterMapHandler = GCHandle.Alloc(_watermap, GCHandleType.Pinned);
2629
2630 d.GeomHeightfieldDataBuildSingle(WaterHeightmapData, WaterMapHandler.AddrOfPinnedObject(), 0, heightmapWidth, heightmapHeight,
2631 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
2632 offset, thickness, wrap);
2633 d.GeomHeightfieldDataSetBounds(WaterHeightmapData, minheigh, maxheigh);
2634 WaterGeom = d.CreateHeightfield(StaticSpace, WaterHeightmapData, 1);
2635 if (WaterGeom != IntPtr.Zero)
2636 {
2637 d.GeomSetCategoryBits(WaterGeom, (uint)(CollisionCategories.Water));
2638 d.GeomSetCollideBits(WaterGeom, 0);
2639
2640 geom_name_map[WaterGeom] = "Water";
2641
2642 d.Matrix3 R = new d.Matrix3();
2643
2644 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
2645 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
2646
2647 q1 = q1 * q2;
2648 Vector3 v3;
2649 float angle;
2650 q1.GetAxisAngle(out v3, out angle);
2651
2652 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
2653 d.GeomSetRotation(WaterGeom, ref R);
2654 d.GeomSetPosition(WaterGeom, (float)Constants.RegionSize * 0.5f, (float)Constants.RegionSize * 0.5f, 0);
2655 }
2656 }
2657 }
2658
2659 public override void Dispose()
2660 {
2661 lock (OdeLock)
2662 {
2663 m_rayCastManager.Dispose();
2664 m_rayCastManager = null;
2665
2666 lock (_prims)
2667 {
2668 ChangesQueue.Clear();
2669 foreach (OdePrim prm in _prims)
2670 {
2671 prm.DoAChange(changes.Remove, null);
2672 _collisionEventPrim.Remove(prm);
2673 }
2674 _prims.Clear();
2675 }
2676
2677 OdeCharacter[] chtorem;
2678 lock (_characters)
2679 {
2680 chtorem = new OdeCharacter[_characters.Count];
2681 _characters.CopyTo(chtorem);
2682 }
2683
2684 ChangesQueue.Clear();
2685 foreach (OdeCharacter ch in chtorem)
2686 ch.DoAChange(changes.Remove, null);
2687
2688
2689 foreach (IntPtr GroundGeom in RegionTerrain.Values)
2690 {
2691 if (GroundGeom != IntPtr.Zero)
2692 d.GeomDestroy(GroundGeom);
2693 }
2694
2695 RegionTerrain.Clear();
2696
2697 if (TerrainHeightFieldHeightsHandlers.Count > 0)
2698 {
2699 foreach (GCHandle gch in TerrainHeightFieldHeightsHandlers.Values)
2700 {
2701 if (gch.IsAllocated)
2702 gch.Free();
2703 }
2704 }
2705
2706 TerrainHeightFieldHeightsHandlers.Clear();
2707 TerrainHeightFieldHeights.Clear();
2708
2709 if (WaterGeom != IntPtr.Zero)
2710 {
2711 d.GeomDestroy(WaterGeom);
2712 WaterGeom = IntPtr.Zero;
2713 if (WaterHeightmapData != IntPtr.Zero)
2714 d.GeomHeightfieldDataDestroy(WaterHeightmapData);
2715 WaterHeightmapData = IntPtr.Zero;
2716
2717 if (WaterMapHandler.IsAllocated)
2718 WaterMapHandler.Free();
2719 }
2720
2721
2722 if (ContactgeomsArray != IntPtr.Zero)
2723 Marshal.FreeHGlobal(ContactgeomsArray);
2724 if (GlobalContactsArray != IntPtr.Zero)
2725 Marshal.FreeHGlobal(GlobalContactsArray);
2726
2727
2728 d.WorldDestroy(world);
2729 world = IntPtr.Zero;
2730 //d.CloseODE();
2731 }
2732 }
2733
2734 public override Dictionary<uint, float> GetTopColliders()
2735 {
2736 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
2737 int cnt = 0;
2738 lock (_prims)
2739 {
2740 foreach (OdePrim prm in _prims)
2741 {
2742 if (prm.CollisionScore > 0)
2743 {
2744 returncolliders.Add(prm.m_localID, prm.CollisionScore);
2745 cnt++;
2746 prm.CollisionScore = 0f;
2747 if (cnt > 25)
2748 {
2749 break;
2750 }
2751 }
2752 }
2753 }
2754 return returncolliders;
2755 }
2756
2757 public override bool SupportsRayCast()
2758 {
2759 return true;
2760 }
2761
2762 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
2763 {
2764 if (retMethod != null)
2765 {
2766 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
2767 }
2768 }
2769
2770 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
2771 {
2772 if (retMethod != null)
2773 {
2774 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
2775 }
2776 }
2777
2778 // don't like this
2779 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
2780 {
2781 ContactResult[] ourResults = null;
2782 RayCallback retMethod = delegate(List<ContactResult> results)
2783 {
2784 ourResults = new ContactResult[results.Count];
2785 results.CopyTo(ourResults, 0);
2786 };
2787 int waitTime = 0;
2788 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
2789 while (ourResults == null && waitTime < 1000)
2790 {
2791 Thread.Sleep(1);
2792 waitTime++;
2793 }
2794 if (ourResults == null)
2795 return new List<ContactResult>();
2796 return new List<ContactResult>(ourResults);
2797 }
2798
2799 public override bool SuportsRaycastWorldFiltered()
2800 {
2801 return true;
2802 }
2803
2804 public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
2805 {
2806 object SyncObject = new object();
2807 List<ContactResult> ourresults = new List<ContactResult>();
2808
2809 RayCallback retMethod = delegate(List<ContactResult> results)
2810 {
2811 lock (SyncObject)
2812 {
2813 ourresults = results;
2814 Monitor.PulseAll(SyncObject);
2815 }
2816 };
2817
2818 lock (SyncObject)
2819 {
2820 m_rayCastManager.QueueRequest(position, direction, length, Count,filter, retMethod);
2821 if (!Monitor.Wait(SyncObject, 500))
2822 return null;
2823 else
2824 return ourresults;
2825 }
2826 }
2827
2828 public override void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
2829 {
2830 if (retMethod != null && actor !=null)
2831 {
2832 IntPtr geom;
2833 if (actor is OdePrim)
2834 geom = ((OdePrim)actor).prim_geom;
2835 else if (actor is OdeCharacter)
2836 geom = ((OdePrim)actor).prim_geom;
2837 else
2838 return;
2839 if (geom == IntPtr.Zero)
2840 return;
2841 m_rayCastManager.QueueRequest(geom, position, direction, length, retMethod);
2842 }
2843 }
2844
2845 public override void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
2846 {
2847 if (retMethod != null && actor != null)
2848 {
2849 IntPtr geom;
2850 if (actor is OdePrim)
2851 geom = ((OdePrim)actor).prim_geom;
2852 else if (actor is OdeCharacter)
2853 geom = ((OdePrim)actor).prim_geom;
2854 else
2855 return;
2856 if (geom == IntPtr.Zero)
2857 return;
2858
2859 m_rayCastManager.QueueRequest(geom,position, direction, length, Count, retMethod);
2860 }
2861 }
2862
2863 // don't like this
2864 public override List<ContactResult> RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count)
2865 {
2866 if (actor != null)
2867 {
2868 IntPtr geom;
2869 if (actor is OdePrim)
2870 geom = ((OdePrim)actor).prim_geom;
2871 else if (actor is OdeCharacter)
2872 geom = ((OdePrim)actor).prim_geom;
2873 else
2874 return new List<ContactResult>();
2875 if (geom == IntPtr.Zero)
2876 return new List<ContactResult>();
2877
2878 ContactResult[] ourResults = null;
2879 RayCallback retMethod = delegate(List<ContactResult> results)
2880 {
2881 ourResults = new ContactResult[results.Count];
2882 results.CopyTo(ourResults, 0);
2883 };
2884 int waitTime = 0;
2885 m_rayCastManager.QueueRequest(geom,position, direction, length, Count, retMethod);
2886 while (ourResults == null && waitTime < 1000)
2887 {
2888 Thread.Sleep(1);
2889 waitTime++;
2890 }
2891 if (ourResults == null)
2892 return new List<ContactResult>();
2893 return new List<ContactResult>(ourResults);
2894 }
2895 return new List<ContactResult>();
2896 }
2897 }
2898}