aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2011-07-08 18:16:48 +0100
committerJustin Clark-Casey (justincc)2011-07-08 18:16:48 +0100
commit36df9ae79a8cd1d4964a42c79e26ad2a226be0ba (patch)
treed87e72836a3ca03a7a96befc9a519e2d366424ff
parentminor: commented out log lines for future use and very small code tidy (diff)
downloadopensim-SC_OLD-36df9ae79a8cd1d4964a42c79e26ad2a226be0ba.zip
opensim-SC_OLD-36df9ae79a8cd1d4964a42c79e26ad2a226be0ba.tar.gz
opensim-SC_OLD-36df9ae79a8cd1d4964a42c79e26ad2a226be0ba.tar.bz2
opensim-SC_OLD-36df9ae79a8cd1d4964a42c79e26ad2a226be0ba.tar.xz
refactor: Separate the OdeScene class into its own file from OdePlugin.cs, to improve code readability
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs3832
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs3866
2 files changed, 3873 insertions, 3825 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index ae9c377..ebd46ab 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
@@ -25,8 +25,6 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28//#define USE_DRAWSTUFF
29
30using System; 28using System;
31using System.Collections.Generic; 29using System.Collections.Generic;
32using System.Reflection; 30using System.Reflection;
@@ -37,15 +35,10 @@ using System.Diagnostics;
37using log4net; 35using log4net;
38using Nini.Config; 36using Nini.Config;
39using Ode.NET; 37using Ode.NET;
40#if USE_DRAWSTUFF
41using Drawstuff.NET;
42#endif
43using OpenSim.Framework; 38using OpenSim.Framework;
44using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
45using OpenMetaverse; 40using OpenMetaverse;
46 41
47//using OpenSim.Region.Physics.OdePlugin.Meshing;
48
49namespace OpenSim.Region.Physics.OdePlugin 42namespace OpenSim.Region.Physics.OdePlugin
50{ 43{
51 /// <summary> 44 /// <summary>
@@ -55,12 +48,12 @@ namespace OpenSim.Region.Physics.OdePlugin
55 { 48 {
56 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 49 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
57 50
58 private CollisionLocker ode; 51 private CollisionLocker m_ode;
59 private OdeScene _mScene; 52 private OdeScene m_scene;
60 53
61 public OdePlugin() 54 public OdePlugin()
62 { 55 {
63 ode = new CollisionLocker(); 56 m_ode = new CollisionLocker();
64 } 57 }
65 58
66 public bool Init() 59 public bool Init()
@@ -70,15 +63,15 @@ namespace OpenSim.Region.Physics.OdePlugin
70 63
71 public PhysicsScene GetScene(String sceneIdentifier) 64 public PhysicsScene GetScene(String sceneIdentifier)
72 { 65 {
73 if (_mScene == null) 66 if (m_scene == null)
74 { 67 {
75 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to 68 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
76 // http://opensimulator.org/mantis/view.php?id=2750). 69 // http://opensimulator.org/mantis/view.php?id=2750).
77 d.InitODE(); 70 d.InitODE();
78 71
79 _mScene = new OdeScene(ode, sceneIdentifier); 72 m_scene = new OdeScene(m_ode, sceneIdentifier);
80 } 73 }
81 return (_mScene); 74 return (m_scene);
82 } 75 }
83 76
84 public string GetName() 77 public string GetName()
@@ -90,3815 +83,4 @@ namespace OpenSim.Region.Physics.OdePlugin
90 { 83 {
91 } 84 }
92 } 85 }
93 86} \ No newline at end of file
94 public enum StatusIndicators : int
95 {
96 Generic = 0,
97 Start = 1,
98 End = 2
99 }
100
101 public struct sCollisionData
102 {
103 public uint ColliderLocalId;
104 public uint CollidedWithLocalId;
105 public int NumberOfCollisions;
106 public int CollisionType;
107 public int StatusIndicator;
108 public int lastframe;
109 }
110
111 [Flags]
112 public enum CollisionCategories : int
113 {
114 Disabled = 0,
115 Geom = 0x00000001,
116 Body = 0x00000002,
117 Space = 0x00000004,
118 Character = 0x00000008,
119 Land = 0x00000010,
120 Water = 0x00000020,
121 Wind = 0x00000040,
122 Sensor = 0x00000080,
123 Selected = 0x00000100
124 }
125
126 /// <summary>
127 /// Material type for a primitive
128 /// </summary>
129 public enum Material : int
130 {
131 /// <summary></summary>
132 Stone = 0,
133 /// <summary></summary>
134 Metal = 1,
135 /// <summary></summary>
136 Glass = 2,
137 /// <summary></summary>
138 Wood = 3,
139 /// <summary></summary>
140 Flesh = 4,
141 /// <summary></summary>
142 Plastic = 5,
143 /// <summary></summary>
144 Rubber = 6
145
146 }
147
148 public sealed class OdeScene : PhysicsScene
149 {
150 private readonly ILog m_log;
151 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
152
153 CollisionLocker ode;
154
155 private Random fluidRandomizer = new Random(Environment.TickCount);
156
157 private const uint m_regionWidth = Constants.RegionSize;
158 private const uint m_regionHeight = Constants.RegionSize;
159
160 private float ODE_STEPSIZE = 0.020f;
161 private float metersInSpace = 29.9f;
162 private float m_timeDilation = 1.0f;
163
164 public float gravityx = 0f;
165 public float gravityy = 0f;
166 public float gravityz = -9.8f;
167
168 private float contactsurfacelayer = 0.001f;
169
170 private int worldHashspaceLow = -4;
171 private int worldHashspaceHigh = 128;
172
173 private int smallHashspaceLow = -4;
174 private int smallHashspaceHigh = 66;
175
176 private float waterlevel = 0f;
177 private int framecount = 0;
178 //private int m_returncollisions = 10;
179
180 private readonly IntPtr contactgroup;
181
182 internal IntPtr LandGeom;
183 internal IntPtr WaterGeom;
184
185 private float nmTerrainContactFriction = 255.0f;
186 private float nmTerrainContactBounce = 0.1f;
187 private float nmTerrainContactERP = 0.1025f;
188
189 private float mTerrainContactFriction = 75f;
190 private float mTerrainContactBounce = 0.1f;
191 private float mTerrainContactERP = 0.05025f;
192
193 private float nmAvatarObjectContactFriction = 250f;
194 private float nmAvatarObjectContactBounce = 0.1f;
195
196 private float mAvatarObjectContactFriction = 75f;
197 private float mAvatarObjectContactBounce = 0.1f;
198
199 private float avPIDD = 3200f;
200 private float avPIDP = 1400f;
201 private float avCapRadius = 0.37f;
202 private float avStandupTensor = 2000000f;
203 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
204 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
205 private float avDensity = 80f;
206 private float avHeightFudgeFactor = 0.52f;
207 private float avMovementDivisorWalk = 1.3f;
208 private float avMovementDivisorRun = 0.8f;
209 private float minimumGroundFlightOffset = 3f;
210 public float maximumMassObject = 10000.01f;
211
212 public bool meshSculptedPrim = true;
213 public bool forceSimplePrimMeshing = false;
214
215 public float meshSculptLOD = 32;
216 public float MeshSculptphysicalLOD = 16;
217
218 public float geomDefaultDensity = 10.000006836f;
219
220 public int geomContactPointsStartthrottle = 3;
221 public int geomUpdatesPerThrottledUpdate = 15;
222
223 public float bodyPIDD = 35f;
224 public float bodyPIDG = 25;
225
226 public int geomCrossingFailuresBeforeOutofbounds = 5;
227
228 public float bodyMotorJointMaxforceTensor = 2;
229
230 public int bodyFramesAutoDisable = 20;
231
232
233
234 private float[] _watermap;
235 private bool m_filterCollisions = true;
236
237 private d.NearCallback nearCallback;
238 public d.TriCallback triCallback;
239 public d.TriArrayCallback triArrayCallback;
240 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
241 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
242 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
243 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
244 private readonly Object _taintedPrimLock = new Object();
245 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
246 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
247 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
248 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
249 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
250 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
251 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
252 private bool m_NINJA_physics_joints_enabled = false;
253 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
254 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
255 private d.ContactGeom[] contacts;
256 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
257 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
258 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
259 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
260 private Object externalJointRequestsLock = new Object();
261 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
262 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
263 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
264 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
265
266 private d.Contact contact;
267 private d.Contact TerrainContact;
268 private d.Contact AvatarMovementprimContact;
269 private d.Contact AvatarMovementTerrainContact;
270 private d.Contact WaterContact;
271 private d.Contact[,] m_materialContacts;
272
273//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
274//Ckrinke private int m_randomizeWater = 200;
275 private int m_physicsiterations = 10;
276 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
277 private readonly PhysicsActor PANull = new NullPhysicsActor();
278 private float step_time = 0.0f;
279//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
280//Ckrinke private int ms = 0;
281 public IntPtr world;
282 //private bool returncollisions = false;
283 // private uint obj1LocalID = 0;
284 private uint obj2LocalID = 0;
285 //private int ctype = 0;
286 private OdeCharacter cc1;
287 private OdePrim cp1;
288 private OdeCharacter cc2;
289 private OdePrim cp2;
290 private int tickCountFrameRun;
291
292 private int latertickcount=0;
293 //private int cStartStop = 0;
294 //private string cDictKey = "";
295
296 public IntPtr space;
297
298 //private IntPtr tmpSpace;
299 // split static geometry collision handling into spaces of 30 meters
300 public IntPtr[,] staticPrimspace;
301
302 public Object OdeLock;
303
304 public IMesher mesher;
305
306 private IConfigSource m_config;
307
308 public bool physics_logging = false;
309 public int physics_logging_interval = 0;
310 public bool physics_logging_append_existing_logfile = false;
311
312 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
313 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
314
315 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
316 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
317 // TODO: unused: private uint heightmapWidthSamples;
318 // TODO: unused: private uint heightmapHeightSamples;
319
320 private volatile int m_global_contactcount = 0;
321
322 private Vector3 m_worldOffset = Vector3.Zero;
323 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
324 private PhysicsScene m_parentScene = null;
325
326 private ODERayCastRequestManager m_rayCastManager;
327
328 /// <summary>
329 /// Initiailizes the scene
330 /// Sets many properties that ODE requires to be stable
331 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
332 /// </summary>
333 public OdeScene(CollisionLocker dode, string sceneIdentifier)
334 {
335 m_log
336 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
337
338 OdeLock = new Object();
339 ode = dode;
340 nearCallback = near;
341 triCallback = TriCallback;
342 triArrayCallback = TriArrayCallback;
343 m_rayCastManager = new ODERayCastRequestManager(this);
344 lock (OdeLock)
345 {
346 // Create the world and the first space
347 world = d.WorldCreate();
348 space = d.HashSpaceCreate(IntPtr.Zero);
349
350
351 contactgroup = d.JointGroupCreate(0);
352 //contactgroup
353
354 d.WorldSetAutoDisableFlag(world, false);
355 #if USE_DRAWSTUFF
356
357 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
358 viewthread.Start();
359 #endif
360 }
361
362
363 _watermap = new float[258 * 258];
364
365 // Zero out the prim spaces array (we split our space into smaller spaces so
366 // we can hit test less.
367 }
368
369#if USE_DRAWSTUFF
370 public void startvisualization(object o)
371 {
372 ds.Functions fn;
373 fn.version = ds.VERSION;
374 fn.start = new ds.CallbackFunction(start);
375 fn.step = new ds.CallbackFunction(step);
376 fn.command = new ds.CallbackFunction(command);
377 fn.stop = null;
378 fn.path_to_textures = "./textures";
379 string[] args = new string[0];
380 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
381 }
382#endif
383
384 // Initialize the mesh plugin
385 public override void Initialise(IMesher meshmerizer, IConfigSource config)
386 {
387 mesher = meshmerizer;
388 m_config = config;
389 // Defaults
390
391 if (Environment.OSVersion.Platform == PlatformID.Unix)
392 {
393 avPIDD = 3200.0f;
394 avPIDP = 1400.0f;
395 avStandupTensor = 2000000f;
396 }
397 else
398 {
399 avPIDD = 2200.0f;
400 avPIDP = 900.0f;
401 avStandupTensor = 550000f;
402 }
403
404 int contactsPerCollision = 80;
405
406 if (m_config != null)
407 {
408 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
409 if (physicsconfig != null)
410 {
411 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
412 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
413 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
414
415 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
416 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
417
418 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
419 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
420 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
421
422 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
423
424 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
425 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
426 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
427
428 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
429 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
430 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
431
432 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
433 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
434
435 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
436 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
437
438 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
439 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
440
441 avDensity = physicsconfig.GetFloat("av_density", 80f);
442 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
443 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
444 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
445 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
446 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
447
448 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
449
450 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
451 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
452 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
453
454 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
455 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
456
457 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
458 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
459
460 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
461 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
462 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
463 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
464 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
465
466 if (Environment.OSVersion.Platform == PlatformID.Unix)
467 {
468 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
469 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
470 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
471 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
472 }
473 else
474 {
475 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
476 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
477 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
478 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
479 }
480
481 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
482 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
483 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
484
485 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
486 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
487 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
488 }
489 }
490
491 contacts = new d.ContactGeom[contactsPerCollision];
492
493 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
494
495 // Centeral contact friction and bounce
496 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
497 // an avatar falls through in Z but not in X or Y when walking on a prim.
498 contact.surface.mode |= d.ContactFlags.SoftERP;
499 contact.surface.mu = nmAvatarObjectContactFriction;
500 contact.surface.bounce = nmAvatarObjectContactBounce;
501 contact.surface.soft_cfm = 0.010f;
502 contact.surface.soft_erp = 0.010f;
503
504 // Terrain contact friction and Bounce
505 // This is the *non* moving version. Use this when an avatar
506 // isn't moving to keep it in place better
507 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
508 TerrainContact.surface.mu = nmTerrainContactFriction;
509 TerrainContact.surface.bounce = nmTerrainContactBounce;
510 TerrainContact.surface.soft_erp = nmTerrainContactERP;
511
512 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
513 WaterContact.surface.mu = 0f; // No friction
514 WaterContact.surface.bounce = 0.0f; // No bounce
515 WaterContact.surface.soft_cfm = 0.010f;
516 WaterContact.surface.soft_erp = 0.010f;
517
518 // Prim contact friction and bounce
519 // THis is the *non* moving version of friction and bounce
520 // Use this when an avatar comes in contact with a prim
521 // and is moving
522 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
523 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
524
525 // Terrain contact friction bounce and various error correcting calculations
526 // Use this when an avatar is in contact with the terrain and moving.
527 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
528 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
529 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
530 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
531
532
533 /*
534 <summary></summary>
535 Stone = 0,
536 /// <summary></summary>
537 Metal = 1,
538 /// <summary></summary>
539 Glass = 2,
540 /// <summary></summary>
541 Wood = 3,
542 /// <summary></summary>
543 Flesh = 4,
544 /// <summary></summary>
545 Plastic = 5,
546 /// <summary></summary>
547 Rubber = 6
548 */
549
550 m_materialContacts = new d.Contact[7,2];
551
552 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
553 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
554 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
555 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
556 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
557 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
558
559 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
560 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
561 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
562 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
563 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
564 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
565
566 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
567 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
568 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
569 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
570 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
571 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
572
573 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
574 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
575 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
576 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
577 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
578 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
579
580 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
581 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
582 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
583 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
584 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
585 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
586
587 /*
588 private float nmAvatarObjectContactFriction = 250f;
589 private float nmAvatarObjectContactBounce = 0.1f;
590
591 private float mAvatarObjectContactFriction = 75f;
592 private float mAvatarObjectContactBounce = 0.1f;
593 */
594 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
595 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
596 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
597 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
598 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
599 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
600
601 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
602 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
603 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
604 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
605 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
606 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
607
608 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
609 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
610 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
611 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
612 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
613 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
614
615 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
616 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
617 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
618 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
619 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
620 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
621
622 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
623 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
624 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
625 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
626 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
627 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
628
629 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
630 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
631 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
632 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
633 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
634 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
635
636 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
637 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
638 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
639 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
640 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
641 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
642
643 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
644 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
645 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
646 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
647 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
648 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
649
650 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
651 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
652 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
653 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
654 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
655 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
656
657 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
658
659 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
660
661 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
662 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
663
664 d.WorldSetLinearDamping(world, 256f);
665 d.WorldSetAngularDamping(world, 256f);
666 d.WorldSetAngularDampingThreshold(world, 256f);
667 d.WorldSetLinearDampingThreshold(world, 256f);
668 d.WorldSetMaxAngularSpeed(world, 256f);
669
670 // Set how many steps we go without running collision testing
671 // This is in addition to the step size.
672 // Essentially Steps * m_physicsiterations
673 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
674 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
675
676
677
678 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
679 {
680 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
681 {
682 staticPrimspace[i, j] = IntPtr.Zero;
683 }
684 }
685 }
686
687 internal void waitForSpaceUnlock(IntPtr space)
688 {
689 //if (space != IntPtr.Zero)
690 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
691 }
692
693 /// <summary>
694 /// Debug space message for printing the space that a prim/avatar is in.
695 /// </summary>
696 /// <param name="pos"></param>
697 /// <returns>Returns which split up space the given position is in.</returns>
698 public string whichspaceamIin(Vector3 pos)
699 {
700 return calculateSpaceForGeom(pos).ToString();
701 }
702
703 #region Collision Detection
704
705 /// <summary>
706 /// This is our near callback. A geometry is near a body
707 /// </summary>
708 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
709 /// <param name="g1">a geometry or space</param>
710 /// <param name="g2">another geometry or space</param>
711 private void near(IntPtr space, IntPtr g1, IntPtr g2)
712 {
713 // no lock here! It's invoked from within Simulate(), which is thread-locked
714
715 // Test if we're colliding a geom with a space.
716 // If so we have to drill down into the space recursively
717
718 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
719 {
720 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
721 return;
722
723 // Separating static prim geometry spaces.
724 // We'll be calling near recursivly if one
725 // of them is a space to find all of the
726 // contact points in the space
727 try
728 {
729 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
730 }
731 catch (AccessViolationException)
732 {
733 m_log.Warn("[PHYSICS]: Unable to collide test a space");
734 return;
735 }
736 //Colliding a space or a geom with a space or a geom. so drill down
737
738 //Collide all geoms in each space..
739 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
740 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
741 return;
742 }
743
744 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
745 return;
746
747 IntPtr b1 = d.GeomGetBody(g1);
748 IntPtr b2 = d.GeomGetBody(g2);
749
750 // d.GeomClassID id = d.GeomGetClass(g1);
751
752 String name1 = null;
753 String name2 = null;
754
755 if (!geom_name_map.TryGetValue(g1, out name1))
756 {
757 name1 = "null";
758 }
759 if (!geom_name_map.TryGetValue(g2, out name2))
760 {
761 name2 = "null";
762 }
763
764 //if (id == d.GeomClassId.TriMeshClass)
765 //{
766 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
767 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
768 //}
769
770 // Figure out how many contact points we have
771 int count = 0;
772 try
773 {
774 // Colliding Geom To Geom
775 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
776
777 if (g1 == g2)
778 return; // Can't collide with yourself
779
780 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
781 return;
782
783 lock (contacts)
784 {
785 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
786 if (count > contacts.Length)
787 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
788 }
789 }
790 catch (SEHException)
791 {
792 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.");
793 ode.drelease(world);
794 base.TriggerPhysicsBasedRestart();
795 }
796 catch (Exception e)
797 {
798 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
799 return;
800 }
801
802 PhysicsActor p1;
803 PhysicsActor p2;
804
805 if (!actor_name_map.TryGetValue(g1, out p1))
806 {
807 p1 = PANull;
808 }
809
810 if (!actor_name_map.TryGetValue(g2, out p2))
811 {
812 p2 = PANull;
813 }
814
815 ContactPoint maxDepthContact = new ContactPoint();
816 if (p1.CollisionScore + count >= float.MaxValue)
817 p1.CollisionScore = 0;
818 p1.CollisionScore += count;
819
820 if (p2.CollisionScore + count >= float.MaxValue)
821 p2.CollisionScore = 0;
822 p2.CollisionScore += count;
823
824 for (int i = 0; i < count; i++)
825 {
826 d.ContactGeom curContact = contacts[i];
827
828 if (curContact.depth > maxDepthContact.PenetrationDepth)
829 {
830 maxDepthContact = new ContactPoint(
831 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
832 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
833 curContact.depth
834 );
835 }
836
837 //m_log.Warn("[CCOUNT]: " + count);
838 IntPtr joint;
839 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
840 // allows us to have different settings
841
842 // We only need to test p2 for 'jump crouch purposes'
843 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
844 {
845 // Testing if the collision is at the feet of the avatar
846
847 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
848 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
849 p2.IsColliding = true;
850 }
851 else
852 {
853 p2.IsColliding = true;
854 }
855
856 //if ((framecount % m_returncollisions) == 0)
857
858 switch (p1.PhysicsActorType)
859 {
860 case (int)ActorTypes.Agent:
861 p2.CollidingObj = true;
862 break;
863 case (int)ActorTypes.Prim:
864 if (p2.Velocity.LengthSquared() > 0.0f)
865 p2.CollidingObj = true;
866 break;
867 case (int)ActorTypes.Unknown:
868 p2.CollidingGround = true;
869 break;
870 default:
871 p2.CollidingGround = true;
872 break;
873 }
874
875 // we don't want prim or avatar to explode
876
877 #region InterPenetration Handling - Unintended physics explosions
878# region disabled code1
879
880 if (curContact.depth >= 0.08f)
881 {
882 //This is disabled at the moment only because it needs more tweaking
883 //It will eventually be uncommented
884 /*
885 if (contact.depth >= 1.00f)
886 {
887 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
888 }
889
890 //If you interpenetrate a prim with an agent
891 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
892 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
893 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
894 p2.PhysicsActorType == (int) ActorTypes.Prim))
895 {
896
897 //contact.depth = contact.depth * 4.15f;
898 /*
899 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
900 {
901 p2.CollidingObj = true;
902 contact.depth = 0.003f;
903 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
904 OdeCharacter character = (OdeCharacter) p2;
905 character.SetPidStatus(true);
906 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
907
908 }
909 else
910 {
911
912 //contact.depth = 0.0000000f;
913 }
914 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
915 {
916
917 p1.CollidingObj = true;
918 contact.depth = 0.003f;
919 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
920 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
921 OdeCharacter character = (OdeCharacter)p1;
922 character.SetPidStatus(true);
923 }
924 else
925 {
926
927 //contact.depth = 0.0000000f;
928 }
929
930
931
932 }
933*/
934 // If you interpenetrate a prim with another prim
935 /*
936 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
937 {
938 #region disabledcode2
939 //OdePrim op1 = (OdePrim)p1;
940 //OdePrim op2 = (OdePrim)p2;
941 //op1.m_collisionscore++;
942 //op2.m_collisionscore++;
943
944 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
945 //{
946 //op1.m_taintdisable = true;
947 //AddPhysicsActorTaint(p1);
948 //op2.m_taintdisable = true;
949 //AddPhysicsActorTaint(p2);
950 //}
951
952 //if (contact.depth >= 0.25f)
953 //{
954 // Don't collide, one or both prim will expld.
955
956 //op1.m_interpenetrationcount++;
957 //op2.m_interpenetrationcount++;
958 //interpenetrations_before_disable = 200;
959 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
960 //{
961 //op1.m_taintdisable = true;
962 //AddPhysicsActorTaint(p1);
963 //}
964 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
965 //{
966 // op2.m_taintdisable = true;
967 //AddPhysicsActorTaint(p2);
968 //}
969
970 //contact.depth = contact.depth / 8f;
971 //contact.normal = new d.Vector3(0, 0, 1);
972 //}
973 //if (op1.m_disabled || op2.m_disabled)
974 //{
975 //Manually disabled objects stay disabled
976 //contact.depth = 0f;
977 //}
978 #endregion
979 }
980 */
981#endregion
982 if (curContact.depth >= 1.00f)
983 {
984 //m_log.Info("[P]: " + contact.depth.ToString());
985 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
986 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
987 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
988 p2.PhysicsActorType == (int) ActorTypes.Unknown))
989 {
990 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
991 {
992 if (p2 is OdeCharacter)
993 {
994 OdeCharacter character = (OdeCharacter) p2;
995
996 //p2.CollidingObj = true;
997 curContact.depth = 0.00000003f;
998 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
999 curContact.pos =
1000 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1001 curContact.pos.Y + (p1.Size.Y/2),
1002 curContact.pos.Z + (p1.Size.Z/2));
1003 character.SetPidStatus(true);
1004 }
1005 }
1006
1007
1008 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1009 {
1010 if (p1 is OdeCharacter)
1011 {
1012 OdeCharacter character = (OdeCharacter) p1;
1013
1014 //p2.CollidingObj = true;
1015 curContact.depth = 0.00000003f;
1016 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1017 curContact.pos =
1018 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1019 curContact.pos.Y + (p1.Size.Y/2),
1020 curContact.pos.Z + (p1.Size.Z/2));
1021 character.SetPidStatus(true);
1022 }
1023 }
1024 }
1025 }
1026 }
1027
1028 #endregion
1029
1030 // Logic for collision handling
1031 // Note, that if *all* contacts are skipped (VolumeDetect)
1032 // The prim still detects (and forwards) collision events but
1033 // appears to be phantom for the world
1034 Boolean skipThisContact = false;
1035
1036 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1037 skipThisContact = true; // No collision on volume detect prims
1038
1039 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1040 skipThisContact = true; // No collision on volume detect prims
1041
1042 if (!skipThisContact && curContact.depth < 0f)
1043 skipThisContact = true;
1044
1045 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1046 skipThisContact = true;
1047
1048 const int maxContactsbeforedeath = 4000;
1049 joint = IntPtr.Zero;
1050
1051 if (!skipThisContact)
1052 {
1053 // If we're colliding against terrain
1054 if (name1 == "Terrain" || name2 == "Terrain")
1055 {
1056 // If we're moving
1057 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1058 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1059 {
1060 // Use the movement terrain contact
1061 AvatarMovementTerrainContact.geom = curContact;
1062 _perloopContact.Add(curContact);
1063 if (m_global_contactcount < maxContactsbeforedeath)
1064 {
1065 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1066 m_global_contactcount++;
1067 }
1068 }
1069 else
1070 {
1071 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1072 {
1073 // Use the non moving terrain contact
1074 TerrainContact.geom = curContact;
1075 _perloopContact.Add(curContact);
1076 if (m_global_contactcount < maxContactsbeforedeath)
1077 {
1078 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1079 m_global_contactcount++;
1080 }
1081 }
1082 else
1083 {
1084 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1085 {
1086 // prim prim contact
1087 // int pj294950 = 0;
1088 int movintYN = 0;
1089 int material = (int) Material.Wood;
1090 // prim terrain contact
1091 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1092 {
1093 movintYN = 1;
1094 }
1095
1096 if (p2 is OdePrim)
1097 material = ((OdePrim)p2).m_material;
1098
1099 //m_log.DebugFormat("Material: {0}", material);
1100 m_materialContacts[material, movintYN].geom = curContact;
1101 _perloopContact.Add(curContact);
1102
1103 if (m_global_contactcount < maxContactsbeforedeath)
1104 {
1105 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1106 m_global_contactcount++;
1107
1108 }
1109
1110 }
1111 else
1112 {
1113
1114 int movintYN = 0;
1115 // prim terrain contact
1116 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1117 {
1118 movintYN = 1;
1119 }
1120
1121 int material = (int)Material.Wood;
1122
1123 if (p2 is OdePrim)
1124 material = ((OdePrim)p2).m_material;
1125 //m_log.DebugFormat("Material: {0}", material);
1126 m_materialContacts[material, movintYN].geom = curContact;
1127 _perloopContact.Add(curContact);
1128
1129 if (m_global_contactcount < maxContactsbeforedeath)
1130 {
1131 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1132 m_global_contactcount++;
1133
1134 }
1135 }
1136 }
1137 }
1138 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1139 //{
1140 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1141 //}
1142 }
1143 else if (name1 == "Water" || name2 == "Water")
1144 {
1145 /*
1146 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1147 {
1148 }
1149 else
1150 {
1151 }
1152 */
1153 //WaterContact.surface.soft_cfm = 0.0000f;
1154 //WaterContact.surface.soft_erp = 0.00000f;
1155 if (curContact.depth > 0.1f)
1156 {
1157 curContact.depth *= 52;
1158 //contact.normal = new d.Vector3(0, 0, 1);
1159 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1160 }
1161 WaterContact.geom = curContact;
1162 _perloopContact.Add(curContact);
1163 if (m_global_contactcount < maxContactsbeforedeath)
1164 {
1165 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1166 m_global_contactcount++;
1167 }
1168 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1169 }
1170 else
1171 {
1172 // we're colliding with prim or avatar
1173 // check if we're moving
1174 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1175 {
1176 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1177 {
1178 // Use the Movement prim contact
1179 AvatarMovementprimContact.geom = curContact;
1180 _perloopContact.Add(curContact);
1181 if (m_global_contactcount < maxContactsbeforedeath)
1182 {
1183 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1184 m_global_contactcount++;
1185 }
1186 }
1187 else
1188 {
1189 // Use the non movement contact
1190 contact.geom = curContact;
1191 _perloopContact.Add(curContact);
1192
1193 if (m_global_contactcount < maxContactsbeforedeath)
1194 {
1195 joint = d.JointCreateContact(world, contactgroup, ref contact);
1196 m_global_contactcount++;
1197 }
1198 }
1199 }
1200 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1201 {
1202 //p1.PhysicsActorType
1203 int material = (int)Material.Wood;
1204
1205 if (p2 is OdePrim)
1206 material = ((OdePrim)p2).m_material;
1207
1208 //m_log.DebugFormat("Material: {0}", material);
1209 m_materialContacts[material, 0].geom = curContact;
1210 _perloopContact.Add(curContact);
1211
1212 if (m_global_contactcount < maxContactsbeforedeath)
1213 {
1214 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1215 m_global_contactcount++;
1216
1217 }
1218 }
1219 }
1220
1221 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1222 {
1223 d.JointAttach(joint, b1, b2);
1224 m_global_contactcount++;
1225 }
1226
1227 }
1228 collision_accounting_events(p1, p2, maxDepthContact);
1229 if (count > geomContactPointsStartthrottle)
1230 {
1231 // If there are more then 3 contact points, it's likely
1232 // that we've got a pile of objects, so ...
1233 // We don't want to send out hundreds of terse updates over and over again
1234 // so lets throttle them and send them again after it's somewhat sorted out.
1235 p2.ThrottleUpdates = true;
1236 }
1237 //m_log.Debug(count.ToString());
1238 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1239 }
1240 }
1241
1242 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1243 {
1244 bool result = false;
1245 //return result;
1246 if (!m_filterCollisions)
1247 return false;
1248
1249 ActorTypes at = (ActorTypes)atype;
1250 lock (_perloopContact)
1251 {
1252 foreach (d.ContactGeom contact in _perloopContact)
1253 {
1254 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1255 //{
1256 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1257 if (at == ActorTypes.Agent)
1258 {
1259 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1260 {
1261
1262 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1263 {
1264 //contactGeom.depth *= .00005f;
1265 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1266 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1267 result = true;
1268 break;
1269 }
1270 else
1271 {
1272 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1273 }
1274 }
1275 else
1276 {
1277 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1278 //int i = 0;
1279 }
1280 }
1281 else if (at == ActorTypes.Prim)
1282 {
1283 //d.AABB aabb1 = new d.AABB();
1284 //d.AABB aabb2 = new d.AABB();
1285
1286 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1287 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1288 //aabb1.
1289 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1290 {
1291 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1292 {
1293 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1294 {
1295 result = true;
1296 break;
1297 }
1298 }
1299 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1300 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1301 }
1302
1303 }
1304
1305 //}
1306
1307 }
1308 }
1309 return result;
1310 }
1311
1312 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1313 {
1314 // obj1LocalID = 0;
1315 //returncollisions = false;
1316 obj2LocalID = 0;
1317 //ctype = 0;
1318 //cStartStop = 0;
1319 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1320 return;
1321
1322 switch ((ActorTypes)p2.PhysicsActorType)
1323 {
1324 case ActorTypes.Agent:
1325 cc2 = (OdeCharacter)p2;
1326
1327 // obj1LocalID = cc2.m_localID;
1328 switch ((ActorTypes)p1.PhysicsActorType)
1329 {
1330 case ActorTypes.Agent:
1331 cc1 = (OdeCharacter)p1;
1332 obj2LocalID = cc1.m_localID;
1333 cc1.AddCollisionEvent(cc2.m_localID, contact);
1334 //ctype = (int)CollisionCategories.Character;
1335
1336 //if (cc1.CollidingObj)
1337 //cStartStop = (int)StatusIndicators.Generic;
1338 //else
1339 //cStartStop = (int)StatusIndicators.Start;
1340
1341 //returncollisions = true;
1342 break;
1343 case ActorTypes.Prim:
1344 if (p1 is OdePrim)
1345 {
1346 cp1 = (OdePrim) p1;
1347 obj2LocalID = cp1.m_localID;
1348 cp1.AddCollisionEvent(cc2.m_localID, contact);
1349 }
1350 //ctype = (int)CollisionCategories.Geom;
1351
1352 //if (cp1.CollidingObj)
1353 //cStartStop = (int)StatusIndicators.Generic;
1354 //else
1355 //cStartStop = (int)StatusIndicators.Start;
1356
1357 //returncollisions = true;
1358 break;
1359
1360 case ActorTypes.Ground:
1361 case ActorTypes.Unknown:
1362 obj2LocalID = 0;
1363 //ctype = (int)CollisionCategories.Land;
1364 //returncollisions = true;
1365 break;
1366 }
1367
1368 cc2.AddCollisionEvent(obj2LocalID, contact);
1369 break;
1370 case ActorTypes.Prim:
1371
1372 if (p2 is OdePrim)
1373 {
1374 cp2 = (OdePrim) p2;
1375
1376 // obj1LocalID = cp2.m_localID;
1377 switch ((ActorTypes) p1.PhysicsActorType)
1378 {
1379 case ActorTypes.Agent:
1380 if (p1 is OdeCharacter)
1381 {
1382 cc1 = (OdeCharacter) p1;
1383 obj2LocalID = cc1.m_localID;
1384 cc1.AddCollisionEvent(cp2.m_localID, contact);
1385 //ctype = (int)CollisionCategories.Character;
1386
1387 //if (cc1.CollidingObj)
1388 //cStartStop = (int)StatusIndicators.Generic;
1389 //else
1390 //cStartStop = (int)StatusIndicators.Start;
1391 //returncollisions = true;
1392 }
1393 break;
1394 case ActorTypes.Prim:
1395
1396 if (p1 is OdePrim)
1397 {
1398 cp1 = (OdePrim) p1;
1399 obj2LocalID = cp1.m_localID;
1400 cp1.AddCollisionEvent(cp2.m_localID, contact);
1401 //ctype = (int)CollisionCategories.Geom;
1402
1403 //if (cp1.CollidingObj)
1404 //cStartStop = (int)StatusIndicators.Generic;
1405 //else
1406 //cStartStop = (int)StatusIndicators.Start;
1407
1408 //returncollisions = true;
1409 }
1410 break;
1411
1412 case ActorTypes.Ground:
1413 case ActorTypes.Unknown:
1414 obj2LocalID = 0;
1415 //ctype = (int)CollisionCategories.Land;
1416
1417 //returncollisions = true;
1418 break;
1419 }
1420
1421 cp2.AddCollisionEvent(obj2LocalID, contact);
1422 }
1423 break;
1424 }
1425 //if (returncollisions)
1426 //{
1427
1428 //lock (m_storedCollisions)
1429 //{
1430 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1431 //if (m_storedCollisions.ContainsKey(cDictKey))
1432 //{
1433 //sCollisionData objd = m_storedCollisions[cDictKey];
1434 //objd.NumberOfCollisions += 1;
1435 //objd.lastframe = framecount;
1436 //m_storedCollisions[cDictKey] = objd;
1437 //}
1438 //else
1439 //{
1440 //sCollisionData objd = new sCollisionData();
1441 //objd.ColliderLocalId = obj1LocalID;
1442 //objd.CollidedWithLocalId = obj2LocalID;
1443 //objd.CollisionType = ctype;
1444 //objd.NumberOfCollisions = 1;
1445 //objd.lastframe = framecount;
1446 //objd.StatusIndicator = cStartStop;
1447 //m_storedCollisions.Add(cDictKey, objd);
1448 //}
1449 //}
1450 // }
1451 }
1452
1453 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1454 {
1455 /* String name1 = null;
1456 String name2 = null;
1457
1458 if (!geom_name_map.TryGetValue(trimesh, out name1))
1459 {
1460 name1 = "null";
1461 }
1462 if (!geom_name_map.TryGetValue(refObject, out name2))
1463 {
1464 name2 = "null";
1465 }
1466
1467 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1468 */
1469 return 1;
1470 }
1471
1472 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1473 {
1474 String name1 = null;
1475 String name2 = null;
1476
1477 if (!geom_name_map.TryGetValue(trimesh, out name1))
1478 {
1479 name1 = "null";
1480 }
1481
1482 if (!geom_name_map.TryGetValue(refObject, out name2))
1483 {
1484 name2 = "null";
1485 }
1486
1487 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1488
1489 d.Vector3 v0 = new d.Vector3();
1490 d.Vector3 v1 = new d.Vector3();
1491 d.Vector3 v2 = new d.Vector3();
1492
1493 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1494 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1495
1496 return 1;
1497 }
1498
1499 /// <summary>
1500 /// This is our collision testing routine in ODE
1501 /// </summary>
1502 /// <param name="timeStep"></param>
1503 private void collision_optimized(float timeStep)
1504 {
1505 _perloopContact.Clear();
1506
1507 lock (_characters)
1508 {
1509 foreach (OdeCharacter chr in _characters)
1510 {
1511 // Reset the collision values to false
1512 // since we don't know if we're colliding yet
1513
1514 // For some reason this can happen. Don't ask...
1515 //
1516 if (chr == null)
1517 continue;
1518
1519 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1520 continue;
1521
1522 chr.IsColliding = false;
1523 chr.CollidingGround = false;
1524 chr.CollidingObj = false;
1525
1526 // test the avatar's geometry for collision with the space
1527 // This will return near and the space that they are the closest to
1528 // And we'll run this again against the avatar and the space segment
1529 // This will return with a bunch of possible objects in the space segment
1530 // and we'll run it again on all of them.
1531 try
1532 {
1533 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1534 }
1535 catch (AccessViolationException)
1536 {
1537 m_log.Warn("[PHYSICS]: Unable to space collide");
1538 }
1539 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1540 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1541 //{
1542 //chr.Position.Z = terrainheight + 10.0f;
1543 //forcedZ = true;
1544 //}
1545 }
1546 }
1547
1548 lock (_activeprims)
1549 {
1550 List<OdePrim> removeprims = null;
1551 foreach (OdePrim chr in _activeprims)
1552 {
1553 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1554 {
1555 try
1556 {
1557 lock (chr)
1558 {
1559 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1560 {
1561 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1562 }
1563 else
1564 {
1565 if (removeprims == null)
1566 {
1567 removeprims = new List<OdePrim>();
1568 }
1569 removeprims.Add(chr);
1570 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1571 }
1572 }
1573 }
1574 catch (AccessViolationException)
1575 {
1576 m_log.Warn("[PHYSICS]: Unable to space collide");
1577 }
1578 }
1579 }
1580 if (removeprims != null)
1581 {
1582 foreach (OdePrim chr in removeprims)
1583 {
1584 _activeprims.Remove(chr);
1585 }
1586 }
1587 }
1588
1589 _perloopContact.Clear();
1590 }
1591
1592 #endregion
1593
1594 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1595 {
1596 m_worldOffset = offset;
1597 WorldExtents = new Vector2(extents.X, extents.Y);
1598 m_parentScene = pScene;
1599
1600 }
1601
1602 // Recovered for use by fly height. Kitto Flora
1603 public float GetTerrainHeightAtXY(float x, float y)
1604 {
1605
1606 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1607 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1608
1609 IntPtr heightFieldGeom = IntPtr.Zero;
1610
1611 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1612 {
1613 if (heightFieldGeom != IntPtr.Zero)
1614 {
1615 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1616 {
1617
1618 int index;
1619
1620
1621 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1622 (int)x < 0.001f || (int)y < 0.001f)
1623 return 0;
1624
1625 x = x - offsetX;
1626 y = y - offsetY;
1627
1628 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1629
1630 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1631 {
1632 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1633 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1634 }
1635
1636 else
1637 return 0f;
1638 }
1639 else
1640 {
1641 return 0f;
1642 }
1643
1644 }
1645 else
1646 {
1647 return 0f;
1648 }
1649
1650 }
1651 else
1652 {
1653 return 0f;
1654 }
1655
1656
1657 }
1658// End recovered. Kitto Flora
1659
1660 public void addCollisionEventReporting(PhysicsActor obj)
1661 {
1662 lock (_collisionEventPrim)
1663 {
1664 if (!_collisionEventPrim.Contains(obj))
1665 _collisionEventPrim.Add(obj);
1666 }
1667 }
1668
1669 public void remCollisionEventReporting(PhysicsActor obj)
1670 {
1671 lock (_collisionEventPrim)
1672 {
1673 if (!_collisionEventPrim.Contains(obj))
1674 _collisionEventPrim.Remove(obj);
1675 }
1676 }
1677
1678 #region Add/Remove Entities
1679
1680 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1681 {
1682 Vector3 pos;
1683 pos.X = position.X;
1684 pos.Y = position.Y;
1685 pos.Z = position.Z;
1686 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1687 newAv.Flying = isFlying;
1688 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1689
1690 return newAv;
1691 }
1692
1693 public void AddCharacter(OdeCharacter chr)
1694 {
1695 lock (_characters)
1696 {
1697 if (!_characters.Contains(chr))
1698 {
1699 _characters.Add(chr);
1700 if (chr.bad)
1701 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1702 }
1703 }
1704 }
1705
1706 public void RemoveCharacter(OdeCharacter chr)
1707 {
1708 lock (_characters)
1709 {
1710 if (_characters.Contains(chr))
1711 {
1712 _characters.Remove(chr);
1713 }
1714 }
1715 }
1716 public void BadCharacter(OdeCharacter chr)
1717 {
1718 lock (_badCharacter)
1719 {
1720 if (!_badCharacter.Contains(chr))
1721 _badCharacter.Add(chr);
1722 }
1723 }
1724
1725 public override void RemoveAvatar(PhysicsActor actor)
1726 {
1727 //m_log.Debug("[PHYSICS]:ODELOCK");
1728 ((OdeCharacter) actor).Destroy();
1729
1730 }
1731
1732 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1733 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1734 {
1735
1736 Vector3 pos = position;
1737 Vector3 siz = size;
1738 Quaternion rot = rotation;
1739
1740 OdePrim newPrim;
1741 lock (OdeLock)
1742 {
1743 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1744
1745 lock (_prims)
1746 _prims.Add(newPrim);
1747 }
1748
1749 return newPrim;
1750 }
1751
1752 public void addActivePrim(OdePrim activatePrim)
1753 {
1754 // adds active prim.. (ones that should be iterated over in collisions_optimized
1755 lock (_activeprims)
1756 {
1757 if (!_activeprims.Contains(activatePrim))
1758 _activeprims.Add(activatePrim);
1759 //else
1760 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1761 }
1762 }
1763
1764 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1765 Vector3 size, Quaternion rotation) //To be removed
1766 {
1767 return AddPrimShape(primName, pbs, position, size, rotation, false);
1768 }
1769
1770 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1771 Vector3 size, Quaternion rotation, bool isPhysical)
1772 {
1773// m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
1774
1775 PhysicsActor result;
1776 IMesh mesh = null;
1777
1778 if (needsMeshing(pbs))
1779 {
1780 try
1781 {
1782 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1783 }
1784 catch(Exception e)
1785 {
1786 m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName);
1787 m_log.Debug(e.ToString());
1788 mesh = null;
1789 return null;
1790 }
1791 }
1792
1793 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1794
1795 return result;
1796 }
1797
1798 public override float TimeDilation
1799 {
1800 get { return m_timeDilation; }
1801 }
1802
1803 public override bool SupportsNINJAJoints
1804 {
1805 get { return m_NINJA_physics_joints_enabled; }
1806 }
1807
1808 // internal utility function: must be called within a lock (OdeLock)
1809 private void InternalAddActiveJoint(PhysicsJoint joint)
1810 {
1811 activeJoints.Add(joint);
1812 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1813 }
1814
1815 // internal utility function: must be called within a lock (OdeLock)
1816 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1817 {
1818 pendingJoints.Add(joint);
1819 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1820 }
1821
1822 // internal utility function: must be called within a lock (OdeLock)
1823 private void InternalRemovePendingJoint(PhysicsJoint joint)
1824 {
1825 pendingJoints.Remove(joint);
1826 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1827 }
1828
1829 // internal utility function: must be called within a lock (OdeLock)
1830 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1831 {
1832 activeJoints.Remove(joint);
1833 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1834 }
1835
1836 public override void DumpJointInfo()
1837 {
1838 string hdr = "[NINJA] JOINTINFO: ";
1839 foreach (PhysicsJoint j in pendingJoints)
1840 {
1841 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1842 }
1843 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1844 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1845 {
1846 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1847 }
1848 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1849 foreach (PhysicsJoint j in activeJoints)
1850 {
1851 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1852 }
1853 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1854 foreach (string jointName in SOPName_to_activeJoint.Keys)
1855 {
1856 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1857 }
1858 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1859
1860 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1861 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1862 foreach (string actorName in joints_connecting_actor.Keys)
1863 {
1864 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1865 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1866 {
1867 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1868 }
1869 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1870 }
1871 }
1872
1873 public override void RequestJointDeletion(string ObjectNameInScene)
1874 {
1875 lock (externalJointRequestsLock)
1876 {
1877 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1878 {
1879 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1880 }
1881 }
1882 }
1883
1884 private void DeleteRequestedJoints()
1885 {
1886 List<string> myRequestedJointsToBeDeleted;
1887 lock (externalJointRequestsLock)
1888 {
1889 // make a local copy of the shared list for processing (threading issues)
1890 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1891 }
1892
1893 foreach (string jointName in myRequestedJointsToBeDeleted)
1894 {
1895 lock (OdeLock)
1896 {
1897 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1898 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1899 {
1900 OdePhysicsJoint joint = null;
1901 if (SOPName_to_activeJoint.ContainsKey(jointName))
1902 {
1903 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1904 InternalRemoveActiveJoint(joint);
1905 }
1906 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1907 {
1908 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1909 InternalRemovePendingJoint(joint);
1910 }
1911
1912 if (joint != null)
1913 {
1914 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1915 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1916 {
1917 string bodyName = joint.BodyNames[iBodyName];
1918 if (bodyName != "NULL")
1919 {
1920 joints_connecting_actor[bodyName].Remove(joint);
1921 if (joints_connecting_actor[bodyName].Count == 0)
1922 {
1923 joints_connecting_actor.Remove(bodyName);
1924 }
1925 }
1926 }
1927
1928 DoJointDeactivated(joint);
1929 if (joint.jointID != IntPtr.Zero)
1930 {
1931 d.JointDestroy(joint.jointID);
1932 joint.jointID = IntPtr.Zero;
1933 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1934 }
1935 else
1936 {
1937 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1938 }
1939 }
1940 else
1941 {
1942 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1943 }
1944 }
1945 else
1946 {
1947 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1948 }
1949 }
1950 }
1951
1952 // remove processed joints from the shared list
1953 lock (externalJointRequestsLock)
1954 {
1955 foreach (string jointName in myRequestedJointsToBeDeleted)
1956 {
1957 requestedJointsToBeDeleted.Remove(jointName);
1958 }
1959 }
1960 }
1961
1962 // for pending joints we don't know if their associated bodies exist yet or not.
1963 // the joint is actually created during processing of the taints
1964 private void CreateRequestedJoints()
1965 {
1966 List<PhysicsJoint> myRequestedJointsToBeCreated;
1967 lock (externalJointRequestsLock)
1968 {
1969 // make a local copy of the shared list for processing (threading issues)
1970 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1971 }
1972
1973 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1974 {
1975 lock (OdeLock)
1976 {
1977 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1978 {
1979 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1980 continue;
1981 }
1982 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1983 {
1984 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1985 continue;
1986 }
1987
1988 InternalAddPendingJoint(joint as OdePhysicsJoint);
1989
1990 if (joint.BodyNames.Count >= 2)
1991 {
1992 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1993 {
1994 string bodyName = joint.BodyNames[iBodyName];
1995 if (bodyName != "NULL")
1996 {
1997 if (!joints_connecting_actor.ContainsKey(bodyName))
1998 {
1999 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
2000 }
2001 joints_connecting_actor[bodyName].Add(joint);
2002 }
2003 }
2004 }
2005 }
2006 }
2007
2008 // remove processed joints from shared list
2009 lock (externalJointRequestsLock)
2010 {
2011 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2012 {
2013 requestedJointsToBeCreated.Remove(joint);
2014 }
2015 }
2016
2017 }
2018
2019 // public function to add an request for joint creation
2020 // this joint will just be added to a waiting list that is NOT processed during the main
2021 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2022
2023 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2024 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2025
2026 {
2027
2028 OdePhysicsJoint joint = new OdePhysicsJoint();
2029 joint.ObjectNameInScene = objectNameInScene;
2030 joint.Type = jointType;
2031 joint.Position = position;
2032 joint.Rotation = rotation;
2033 joint.RawParams = parms;
2034 joint.BodyNames = new List<string>(bodyNames);
2035 joint.TrackedBodyName = trackedBodyName;
2036 joint.LocalRotation = localRotation;
2037 joint.jointID = IntPtr.Zero;
2038 joint.ErrorMessageCount = 0;
2039
2040 lock (externalJointRequestsLock)
2041 {
2042 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2043 {
2044 requestedJointsToBeCreated.Add(joint);
2045 }
2046 }
2047 return joint;
2048 }
2049
2050 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2051 {
2052 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2053 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2054 {
2055
2056 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2057 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2058 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2059 {
2060 jointsToRemove.Add(j);
2061 }
2062 foreach (PhysicsJoint j in jointsToRemove)
2063 {
2064 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2065 RequestJointDeletion(j.ObjectNameInScene);
2066 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2067 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2068 }
2069 }
2070 }
2071
2072 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2073 {
2074 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2075 lock (OdeLock)
2076 {
2077 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2078 RemoveAllJointsConnectedToActor(actor);
2079 }
2080 }
2081
2082 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2083 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2084 {
2085 Debug.Assert(joint.IsInPhysicsEngine);
2086 d.Vector3 pos = new d.Vector3();
2087
2088 if (!(joint is OdePhysicsJoint))
2089 {
2090 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2091 }
2092 else
2093 {
2094 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2095 switch (odeJoint.Type)
2096 {
2097 case PhysicsJointType.Ball:
2098 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2099 break;
2100 case PhysicsJointType.Hinge:
2101 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2102 break;
2103 }
2104 }
2105 return new Vector3(pos.X, pos.Y, pos.Z);
2106 }
2107
2108 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2109 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2110 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2111 // keeping track of the joint's original orientation relative to one of the involved bodies.
2112 public override Vector3 GetJointAxis(PhysicsJoint joint)
2113 {
2114 Debug.Assert(joint.IsInPhysicsEngine);
2115 d.Vector3 axis = new d.Vector3();
2116
2117 if (!(joint is OdePhysicsJoint))
2118 {
2119 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2120 }
2121 else
2122 {
2123 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2124 switch (odeJoint.Type)
2125 {
2126 case PhysicsJointType.Ball:
2127 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2128 break;
2129 case PhysicsJointType.Hinge:
2130 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2131 break;
2132 }
2133 }
2134 return new Vector3(axis.X, axis.Y, axis.Z);
2135 }
2136
2137
2138 public void remActivePrim(OdePrim deactivatePrim)
2139 {
2140 lock (_activeprims)
2141 {
2142 _activeprims.Remove(deactivatePrim);
2143 }
2144 }
2145
2146 public override void RemovePrim(PhysicsActor prim)
2147 {
2148 if (prim is OdePrim)
2149 {
2150 lock (OdeLock)
2151 {
2152 OdePrim p = (OdePrim) prim;
2153
2154 p.setPrimForRemoval();
2155 AddPhysicsActorTaint(prim);
2156 //RemovePrimThreadLocked(p);
2157 }
2158 }
2159 }
2160
2161 /// <summary>
2162 /// This is called from within simulate but outside the locked portion
2163 /// We need to do our own locking here
2164 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2165 ///
2166 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2167 /// that the space was using.
2168 /// </summary>
2169 /// <param name="prim"></param>
2170 public void RemovePrimThreadLocked(OdePrim prim)
2171 {
2172//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2173 lock (prim)
2174 {
2175 remCollisionEventReporting(prim);
2176 lock (ode)
2177 {
2178 if (prim.prim_geom != IntPtr.Zero)
2179 {
2180 prim.ResetTaints();
2181
2182 if (prim.IsPhysical)
2183 {
2184 prim.disableBody();
2185 if (prim.childPrim)
2186 {
2187 prim.childPrim = false;
2188 prim.Body = IntPtr.Zero;
2189 prim.m_disabled = true;
2190 prim.IsPhysical = false;
2191 }
2192
2193
2194 }
2195 // we don't want to remove the main space
2196
2197 // If the geometry is in the targetspace, remove it from the target space
2198 //m_log.Warn(prim.m_targetSpace);
2199
2200 //if (prim.m_targetSpace != IntPtr.Zero)
2201 //{
2202 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2203 //{
2204
2205 //if (d.GeomIsSpace(prim.m_targetSpace))
2206 //{
2207 //waitForSpaceUnlock(prim.m_targetSpace);
2208 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2209 prim.m_targetSpace = IntPtr.Zero;
2210 //}
2211 //else
2212 //{
2213 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2214 //((OdePrim)prim).m_targetSpace.ToString());
2215 //}
2216
2217 //}
2218 //}
2219 //m_log.Warn(prim.prim_geom);
2220 try
2221 {
2222 if (prim.prim_geom != IntPtr.Zero)
2223 {
2224 d.GeomDestroy(prim.prim_geom);
2225 prim.prim_geom = IntPtr.Zero;
2226 }
2227 else
2228 {
2229 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2230 }
2231 }
2232 catch (AccessViolationException)
2233 {
2234 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2235 }
2236 lock (_prims)
2237 _prims.Remove(prim);
2238
2239 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2240 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2241 //{
2242 //if (prim.m_targetSpace != null)
2243 //{
2244 //if (d.GeomIsSpace(prim.m_targetSpace))
2245 //{
2246 //waitForSpaceUnlock(prim.m_targetSpace);
2247 //d.SpaceRemove(space, prim.m_targetSpace);
2248 // free up memory used by the space.
2249 //d.SpaceDestroy(prim.m_targetSpace);
2250 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2251 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2252 //}
2253 //else
2254 //{
2255 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2256 //((OdePrim) prim).m_targetSpace.ToString());
2257 //}
2258 //}
2259 //}
2260
2261 if (SupportsNINJAJoints)
2262 {
2263 RemoveAllJointsConnectedToActorThreadLocked(prim);
2264 }
2265 }
2266 }
2267 }
2268 }
2269
2270 #endregion
2271
2272 #region Space Separation Calculation
2273
2274 /// <summary>
2275 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2276 /// </summary>
2277 /// <param name="pSpace"></param>
2278 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2279 {
2280 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2281 {
2282 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2283 {
2284 if (staticPrimspace[x, y] == pSpace)
2285 staticPrimspace[x, y] = IntPtr.Zero;
2286 }
2287 }
2288 }
2289
2290 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2291 {
2292 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2293 }
2294
2295 /// <summary>
2296 /// Called when a static prim moves. Allocates a space for the prim based on its position
2297 /// </summary>
2298 /// <param name="geom">the pointer to the geom that moved</param>
2299 /// <param name="pos">the position that the geom moved to</param>
2300 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2301 /// <returns>a pointer to the new space it's in</returns>
2302 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2303 {
2304 // Called from setting the Position and Size of an ODEPrim so
2305 // it's already in locked space.
2306
2307 // we don't want to remove the main space
2308 // we don't need to test physical here because this function should
2309 // never be called if the prim is physical(active)
2310
2311 // All physical prim end up in the root space
2312 //Thread.Sleep(20);
2313 if (currentspace != space)
2314 {
2315 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2316 //if (currentspace == IntPtr.Zero)
2317 //{
2318 //int adfadf = 0;
2319 //}
2320 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2321 {
2322 if (d.GeomIsSpace(currentspace))
2323 {
2324 waitForSpaceUnlock(currentspace);
2325 d.SpaceRemove(currentspace, geom);
2326 }
2327 else
2328 {
2329 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2330 " Geom:" + geom);
2331 }
2332 }
2333 else
2334 {
2335 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2336 if (sGeomIsIn != IntPtr.Zero)
2337 {
2338 if (d.GeomIsSpace(currentspace))
2339 {
2340 waitForSpaceUnlock(sGeomIsIn);
2341 d.SpaceRemove(sGeomIsIn, geom);
2342 }
2343 else
2344 {
2345 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2346 sGeomIsIn + " Geom:" + geom);
2347 }
2348 }
2349 }
2350
2351 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2352 if (d.SpaceGetNumGeoms(currentspace) == 0)
2353 {
2354 if (currentspace != IntPtr.Zero)
2355 {
2356 if (d.GeomIsSpace(currentspace))
2357 {
2358 waitForSpaceUnlock(currentspace);
2359 waitForSpaceUnlock(space);
2360 d.SpaceRemove(space, currentspace);
2361 // free up memory used by the space.
2362
2363 //d.SpaceDestroy(currentspace);
2364 resetSpaceArrayItemToZero(currentspace);
2365 }
2366 else
2367 {
2368 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2369 currentspace + " Geom:" + geom);
2370 }
2371 }
2372 }
2373 }
2374 else
2375 {
2376 // this is a physical object that got disabled. ;.;
2377 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2378 {
2379 if (d.SpaceQuery(currentspace, geom))
2380 {
2381 if (d.GeomIsSpace(currentspace))
2382 {
2383 waitForSpaceUnlock(currentspace);
2384 d.SpaceRemove(currentspace, geom);
2385 }
2386 else
2387 {
2388 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2389 currentspace + " Geom:" + geom);
2390 }
2391 }
2392 else
2393 {
2394 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2395 if (sGeomIsIn != IntPtr.Zero)
2396 {
2397 if (d.GeomIsSpace(sGeomIsIn))
2398 {
2399 waitForSpaceUnlock(sGeomIsIn);
2400 d.SpaceRemove(sGeomIsIn, geom);
2401 }
2402 else
2403 {
2404 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2405 sGeomIsIn + " Geom:" + geom);
2406 }
2407 }
2408 }
2409 }
2410 }
2411
2412 // The routines in the Position and Size sections do the 'inserting' into the space,
2413 // so all we have to do is make sure that the space that we're putting the prim into
2414 // is in the 'main' space.
2415 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2416 IntPtr newspace = calculateSpaceForGeom(pos);
2417
2418 if (newspace == IntPtr.Zero)
2419 {
2420 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2421 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2422 }
2423
2424 return newspace;
2425 }
2426
2427 /// <summary>
2428 /// Creates a new space at X Y
2429 /// </summary>
2430 /// <param name="iprimspaceArrItemX"></param>
2431 /// <param name="iprimspaceArrItemY"></param>
2432 /// <returns>A pointer to the created space</returns>
2433 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2434 {
2435 // creating a new space for prim and inserting it into main space.
2436 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2437 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2438 waitForSpaceUnlock(space);
2439 d.SpaceSetSublevel(space, 1);
2440 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2441 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2442 }
2443
2444 /// <summary>
2445 /// Calculates the space the prim should be in by its position
2446 /// </summary>
2447 /// <param name="pos"></param>
2448 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2449 public IntPtr calculateSpaceForGeom(Vector3 pos)
2450 {
2451 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2452 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2453 return staticPrimspace[xyspace[0], xyspace[1]];
2454 }
2455
2456 /// <summary>
2457 /// Holds the space allocation logic
2458 /// </summary>
2459 /// <param name="pos"></param>
2460 /// <returns>an array item based on the position</returns>
2461 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2462 {
2463 int[] returnint = new int[2];
2464
2465 returnint[0] = (int) (pos.X/metersInSpace);
2466
2467 if (returnint[0] > ((int) (259f/metersInSpace)))
2468 returnint[0] = ((int) (259f/metersInSpace));
2469 if (returnint[0] < 0)
2470 returnint[0] = 0;
2471
2472 returnint[1] = (int) (pos.Y/metersInSpace);
2473 if (returnint[1] > ((int) (259f/metersInSpace)))
2474 returnint[1] = ((int) (259f/metersInSpace));
2475 if (returnint[1] < 0)
2476 returnint[1] = 0;
2477
2478 return returnint;
2479 }
2480
2481 #endregion
2482
2483 /// <summary>
2484 /// Routine to figure out if we need to mesh this prim with our mesher
2485 /// </summary>
2486 /// <param name="pbs"></param>
2487 /// <returns></returns>
2488 public bool needsMeshing(PrimitiveBaseShape pbs)
2489 {
2490 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2491 // but we still need to check for sculptie meshing being enabled so this is the most
2492 // convenient place to do it for now...
2493
2494 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2495 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2496 int iPropertiesNotSupportedDefault = 0;
2497
2498 if (pbs.SculptEntry && !meshSculptedPrim)
2499 {
2500#if SPAM
2501 m_log.Warn("NonMesh");
2502#endif
2503 return false;
2504 }
2505
2506 // 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
2507 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2508 {
2509 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2510 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2511 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2512 {
2513
2514 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2515 && pbs.ProfileHollow == 0
2516 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2517 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2518 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2519 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2520 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2521 {
2522#if SPAM
2523 m_log.Warn("NonMesh");
2524#endif
2525 return false;
2526 }
2527 }
2528 }
2529
2530 if (pbs.ProfileHollow != 0)
2531 iPropertiesNotSupportedDefault++;
2532
2533 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2534 iPropertiesNotSupportedDefault++;
2535
2536 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2537 iPropertiesNotSupportedDefault++;
2538
2539 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2540 iPropertiesNotSupportedDefault++;
2541
2542 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2543 iPropertiesNotSupportedDefault++;
2544
2545 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2546 iPropertiesNotSupportedDefault++;
2547
2548 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2549 iPropertiesNotSupportedDefault++;
2550
2551 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))
2552 iPropertiesNotSupportedDefault++;
2553
2554 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2555 iPropertiesNotSupportedDefault++;
2556
2557 // test for torus
2558 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2559 {
2560 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2561 {
2562 iPropertiesNotSupportedDefault++;
2563 }
2564 }
2565 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2566 {
2567 if (pbs.PathCurve == (byte)Extrusion.Straight)
2568 {
2569 iPropertiesNotSupportedDefault++;
2570 }
2571
2572 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2573 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2574 {
2575 iPropertiesNotSupportedDefault++;
2576 }
2577 }
2578 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2579 {
2580 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2581 {
2582 iPropertiesNotSupportedDefault++;
2583 }
2584 }
2585 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2586 {
2587 if (pbs.PathCurve == (byte)Extrusion.Straight)
2588 {
2589 iPropertiesNotSupportedDefault++;
2590 }
2591 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2592 {
2593 iPropertiesNotSupportedDefault++;
2594 }
2595 }
2596
2597 if (pbs.SculptEntry && meshSculptedPrim)
2598 iPropertiesNotSupportedDefault++;
2599
2600
2601 if (iPropertiesNotSupportedDefault == 0)
2602 {
2603#if SPAM
2604 m_log.Warn("NonMesh");
2605#endif
2606 return false;
2607 }
2608#if SPAM
2609 m_log.Debug("Mesh");
2610#endif
2611 return true;
2612 }
2613
2614 /// <summary>
2615 /// Called after our prim properties are set Scale, position etc.
2616 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2617 /// This assures us that we have no race conditions
2618 /// </summary>
2619 /// <param name="prim"></param>
2620 public override void AddPhysicsActorTaint(PhysicsActor prim)
2621 {
2622
2623 if (prim is OdePrim)
2624 {
2625 OdePrim taintedprim = ((OdePrim) prim);
2626 lock (_taintedPrimLock)
2627 {
2628 if (!(_taintedPrimH.Contains(taintedprim)))
2629 {
2630//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2631 _taintedPrimH.Add(taintedprim); // HashSet for searching
2632 _taintedPrimL.Add(taintedprim); // List for ordered readout
2633 }
2634 }
2635 return;
2636 }
2637 else if (prim is OdeCharacter)
2638 {
2639 OdeCharacter taintedchar = ((OdeCharacter)prim);
2640 lock (_taintedActors)
2641 {
2642 if (!(_taintedActors.Contains(taintedchar)))
2643 {
2644 _taintedActors.Add(taintedchar);
2645 if (taintedchar.bad)
2646 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2647 }
2648 }
2649 }
2650 }
2651
2652 /// <summary>
2653 /// This is our main simulate loop
2654 /// It's thread locked by a Mutex in the scene.
2655 /// It holds Collisions, it instructs ODE to step through the physical reactions
2656 /// It moves the objects around in memory
2657 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2658 /// </summary>
2659 /// <param name="timeStep"></param>
2660 /// <returns></returns>
2661 public override float Simulate(float timeStep)
2662 {
2663 if (framecount >= int.MaxValue)
2664 framecount = 0;
2665
2666 //if (m_worldOffset != Vector3.Zero)
2667 // return 0;
2668
2669 framecount++;
2670
2671 float fps = 0;
2672 //m_log.Info(timeStep.ToString());
2673 step_time += timeStep;
2674
2675 // If We're loaded down by something else,
2676 // or debugging with the Visual Studio project on pause
2677 // skip a few frames to catch up gracefully.
2678 // without shooting the physicsactors all over the place
2679
2680 if (step_time >= m_SkipFramesAtms)
2681 {
2682 // Instead of trying to catch up, it'll do 5 physics frames only
2683 step_time = ODE_STEPSIZE;
2684 m_physicsiterations = 5;
2685 }
2686 else
2687 {
2688 m_physicsiterations = 10;
2689 }
2690
2691 if (SupportsNINJAJoints)
2692 {
2693 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2694 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2695 }
2696
2697 lock (OdeLock)
2698 {
2699 // Process 10 frames if the sim is running normal..
2700 // process 5 frames if the sim is running slow
2701 //try
2702 //{
2703 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2704 //}
2705 //catch (StackOverflowException)
2706 //{
2707 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2708 // ode.drelease(world);
2709 //base.TriggerPhysicsBasedRestart();
2710 //}
2711
2712 int i = 0;
2713
2714 // Figure out the Frames Per Second we're going at.
2715 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2716
2717 fps = (step_time / ODE_STEPSIZE) * 1000;
2718 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2719 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2720
2721 step_time = 0.09375f;
2722
2723 while (step_time > 0.0f)
2724 {
2725 //lock (ode)
2726 //{
2727 //if (!ode.lockquery())
2728 //{
2729 // ode.dlock(world);
2730 try
2731 {
2732 // Insert, remove Characters
2733 bool processedtaints = false;
2734
2735 lock (_taintedActors)
2736 {
2737 if (_taintedActors.Count > 0)
2738 {
2739 foreach (OdeCharacter character in _taintedActors)
2740 {
2741
2742 character.ProcessTaints(timeStep);
2743
2744 processedtaints = true;
2745 //character.m_collisionscore = 0;
2746 }
2747
2748 if (processedtaints)
2749 _taintedActors.Clear();
2750 }
2751 }
2752
2753 // Modify other objects in the scene.
2754 processedtaints = false;
2755
2756 lock (_taintedPrimLock)
2757 {
2758 foreach (OdePrim prim in _taintedPrimL)
2759 {
2760 if (prim.m_taintremove)
2761 {
2762 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2763 RemovePrimThreadLocked(prim);
2764 }
2765 else
2766 {
2767 //Console.WriteLine("Simulate calls ProcessTaints");
2768 prim.ProcessTaints(timeStep);
2769 }
2770 processedtaints = true;
2771 prim.m_collisionscore = 0;
2772
2773 // This loop can block up the Heartbeat for a very long time on large regions.
2774 // We need to let the Watchdog know that the Heartbeat is not dead
2775 // NOTE: This is currently commented out, but if things like OAR loading are
2776 // timing the heartbeat out we will need to uncomment it
2777 //Watchdog.UpdateThread();
2778 }
2779
2780 if (SupportsNINJAJoints)
2781 {
2782 // Create pending joints, if possible
2783
2784 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2785 // a joint requires specifying the body id of both involved bodies
2786 if (pendingJoints.Count > 0)
2787 {
2788 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2789 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2790 foreach (PhysicsJoint joint in pendingJoints)
2791 {
2792 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2793 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2794 List<IntPtr> jointBodies = new List<IntPtr>();
2795 bool allJointBodiesAreReady = true;
2796 foreach (string jointParam in jointParams)
2797 {
2798 if (jointParam == "NULL")
2799 {
2800 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2801 jointBodies.Add(IntPtr.Zero);
2802 }
2803 else
2804 {
2805 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2806 bool foundPrim = false;
2807 lock (_prims)
2808 {
2809 foreach (OdePrim prim in _prims) // FIXME: inefficient
2810 {
2811 if (prim.SOPName == jointParam)
2812 {
2813 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2814 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2815 {
2816 jointBodies.Add(prim.Body);
2817 foundPrim = true;
2818 break;
2819 }
2820 else
2821 {
2822 DoJointErrorMessage(joint, "prim name " + jointParam +
2823 " exists but is not (yet) physical; deferring joint creation. " +
2824 "IsPhysical property is " + prim.IsPhysical +
2825 " and body is " + prim.Body);
2826 foundPrim = false;
2827 break;
2828 }
2829 }
2830 }
2831 }
2832 if (foundPrim)
2833 {
2834 // all is fine
2835 }
2836 else
2837 {
2838 allJointBodiesAreReady = false;
2839 break;
2840 }
2841 }
2842 }
2843 if (allJointBodiesAreReady)
2844 {
2845 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2846 if (jointBodies[0] == jointBodies[1])
2847 {
2848 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2849 }
2850 else
2851 {
2852 switch (joint.Type)
2853 {
2854 case PhysicsJointType.Ball:
2855 {
2856 IntPtr odeJoint;
2857 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2858 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2859 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2860 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2861 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2862 d.JointSetBallAnchor(odeJoint,
2863 joint.Position.X,
2864 joint.Position.Y,
2865 joint.Position.Z);
2866 //DoJointErrorMessage(joint, "ODE joint setting OK");
2867 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2868 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2869 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2870 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2871
2872 if (joint is OdePhysicsJoint)
2873 {
2874 ((OdePhysicsJoint)joint).jointID = odeJoint;
2875 }
2876 else
2877 {
2878 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2879 }
2880 }
2881 break;
2882 case PhysicsJointType.Hinge:
2883 {
2884 IntPtr odeJoint;
2885 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2886 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2887 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2888 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2889 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2890 d.JointSetHingeAnchor(odeJoint,
2891 joint.Position.X,
2892 joint.Position.Y,
2893 joint.Position.Z);
2894 // We use the orientation of the x-axis of the joint's coordinate frame
2895 // as the axis for the hinge.
2896
2897 // Therefore, we must get the joint's coordinate frame based on the
2898 // joint.Rotation field, which originates from the orientation of the
2899 // joint's proxy object in the scene.
2900
2901 // The joint's coordinate frame is defined as the transformation matrix
2902 // that converts a vector from joint-local coordinates into world coordinates.
2903 // World coordinates are defined as the XYZ coordinate system of the sim,
2904 // as shown in the top status-bar of the viewer.
2905
2906 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2907 // and use that as the hinge axis.
2908
2909 //joint.Rotation.Normalize();
2910 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2911
2912 // Now extract the X axis of the joint's coordinate frame.
2913
2914 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2915 // tar pit of transposed, inverted, and generally messed-up orientations.
2916 // (In other words, Matrix4.AtAxis() is borked.)
2917 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2918
2919 // Instead, compute the X axis of the coordinate frame by transforming
2920 // the (1,0,0) vector. At least that works.
2921
2922 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2923 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2924 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2925 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2926 d.JointSetHingeAxis(odeJoint,
2927 jointAxis.X,
2928 jointAxis.Y,
2929 jointAxis.Z);
2930 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2931 if (joint is OdePhysicsJoint)
2932 {
2933 ((OdePhysicsJoint)joint).jointID = odeJoint;
2934 }
2935 else
2936 {
2937 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2938 }
2939 }
2940 break;
2941 }
2942 successfullyProcessedPendingJoints.Add(joint);
2943 }
2944 }
2945 else
2946 {
2947 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2948 }
2949 }
2950 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2951 {
2952 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2953 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2954 InternalRemovePendingJoint(successfullyProcessedJoint);
2955 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2956 InternalAddActiveJoint(successfullyProcessedJoint);
2957 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2958 }
2959 }
2960 }
2961
2962 if (processedtaints)
2963//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2964 _taintedPrimH.Clear();
2965 _taintedPrimL.Clear();
2966 }
2967
2968 // Move characters
2969 lock (_characters)
2970 {
2971 List<OdeCharacter> defects = new List<OdeCharacter>();
2972 foreach (OdeCharacter actor in _characters)
2973 {
2974 if (actor != null)
2975 actor.Move(timeStep, defects);
2976 }
2977 if (0 != defects.Count)
2978 {
2979 foreach (OdeCharacter defect in defects)
2980 {
2981 RemoveCharacter(defect);
2982 }
2983 }
2984 }
2985
2986 // Move other active objects
2987 lock (_activeprims)
2988 {
2989 foreach (OdePrim prim in _activeprims)
2990 {
2991 prim.m_collisionscore = 0;
2992 prim.Move(timeStep);
2993 }
2994 }
2995
2996 //if ((framecount % m_randomizeWater) == 0)
2997 // randomizeWater(waterlevel);
2998
2999 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
3000 m_rayCastManager.ProcessQueuedRequests();
3001
3002 collision_optimized(timeStep);
3003
3004 lock (_collisionEventPrim)
3005 {
3006 foreach (PhysicsActor obj in _collisionEventPrim)
3007 {
3008 if (obj == null)
3009 continue;
3010
3011 switch ((ActorTypes)obj.PhysicsActorType)
3012 {
3013 case ActorTypes.Agent:
3014 OdeCharacter cobj = (OdeCharacter)obj;
3015 cobj.AddCollisionFrameTime(100);
3016 cobj.SendCollisions();
3017 break;
3018 case ActorTypes.Prim:
3019 OdePrim pobj = (OdePrim)obj;
3020 pobj.SendCollisions();
3021 break;
3022 }
3023 }
3024 }
3025
3026 //if (m_global_contactcount > 5)
3027 //{
3028 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3029 //}
3030
3031 m_global_contactcount = 0;
3032
3033 d.WorldQuickStep(world, ODE_STEPSIZE);
3034 d.JointGroupEmpty(contactgroup);
3035 //ode.dunlock(world);
3036 }
3037 catch (Exception e)
3038 {
3039 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3040 ode.dunlock(world);
3041 }
3042
3043 step_time -= ODE_STEPSIZE;
3044 i++;
3045 //}
3046 //else
3047 //{
3048 //fps = 0;
3049 //}
3050 //}
3051 }
3052
3053 lock (_characters)
3054 {
3055 foreach (OdeCharacter actor in _characters)
3056 {
3057 if (actor != null)
3058 {
3059 if (actor.bad)
3060 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3061 actor.UpdatePositionAndVelocity();
3062 }
3063 }
3064 }
3065
3066 lock (_badCharacter)
3067 {
3068 if (_badCharacter.Count > 0)
3069 {
3070 foreach (OdeCharacter chr in _badCharacter)
3071 {
3072 RemoveCharacter(chr);
3073 }
3074 _badCharacter.Clear();
3075 }
3076 }
3077
3078 lock (_activeprims)
3079 {
3080 //if (timeStep < 0.2f)
3081 {
3082 foreach (OdePrim actor in _activeprims)
3083 {
3084 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3085 {
3086 actor.UpdatePositionAndVelocity();
3087
3088 if (SupportsNINJAJoints)
3089 {
3090 // If an actor moved, move its joint proxy objects as well.
3091 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3092 // for this purpose but it is never called! So we just do the joint
3093 // movement code here.
3094
3095 if (actor.SOPName != null &&
3096 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3097 joints_connecting_actor[actor.SOPName] != null &&
3098 joints_connecting_actor[actor.SOPName].Count > 0)
3099 {
3100 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3101 {
3102 if (affectedJoint.IsInPhysicsEngine)
3103 {
3104 DoJointMoved(affectedJoint);
3105 }
3106 else
3107 {
3108 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3109 }
3110 }
3111 }
3112 }
3113 }
3114 }
3115 }
3116 }
3117
3118 //DumpJointInfo();
3119
3120 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3121 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3122 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3123 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3124 {
3125 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3126 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3127
3128 if (physics_logging_append_existing_logfile)
3129 {
3130 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3131 TextWriter fwriter = File.AppendText(fname);
3132 fwriter.WriteLine(header);
3133 fwriter.Close();
3134 }
3135 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3136 }
3137 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
3138
3139 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3140 // has a max of 100 ms to run theoretically.
3141 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3142 // If Physics stalls, it takes longer which makes the tick count ms larger.
3143
3144 if (latertickcount < 100)
3145 m_timeDilation = 1.0f;
3146 else
3147 {
3148 m_timeDilation = 100f / latertickcount;
3149 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3150 }
3151
3152 tickCountFrameRun = Util.EnvironmentTickCount();
3153 }
3154
3155 return fps;
3156 }
3157
3158 public override void GetResults()
3159 {
3160 }
3161
3162 public override bool IsThreaded
3163 {
3164 // for now we won't be multithreaded
3165 get { return (false); }
3166 }
3167
3168 #region ODE Specific Terrain Fixes
3169 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3170 {
3171 float[] returnarr = new float[262144];
3172 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3173
3174 // Filling out the array into its multi-dimensional components
3175 for (int y = 0; y < WorldExtents.Y; y++)
3176 {
3177 for (int x = 0; x < WorldExtents.X; x++)
3178 {
3179 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3180 }
3181 }
3182
3183 // Resize using Nearest Neighbour
3184
3185 // This particular way is quick but it only works on a multiple of the original
3186
3187 // The idea behind this method can be described with the following diagrams
3188 // second pass and third pass happen in the same loop really.. just separated
3189 // them to show what this does.
3190
3191 // First Pass
3192 // ResultArr:
3193 // 1,1,1,1,1,1
3194 // 1,1,1,1,1,1
3195 // 1,1,1,1,1,1
3196 // 1,1,1,1,1,1
3197 // 1,1,1,1,1,1
3198 // 1,1,1,1,1,1
3199
3200 // Second Pass
3201 // ResultArr2:
3202 // 1,,1,,1,,1,,1,,1,
3203 // ,,,,,,,,,,
3204 // 1,,1,,1,,1,,1,,1,
3205 // ,,,,,,,,,,
3206 // 1,,1,,1,,1,,1,,1,
3207 // ,,,,,,,,,,
3208 // 1,,1,,1,,1,,1,,1,
3209 // ,,,,,,,,,,
3210 // 1,,1,,1,,1,,1,,1,
3211 // ,,,,,,,,,,
3212 // 1,,1,,1,,1,,1,,1,
3213
3214 // Third pass fills in the blanks
3215 // ResultArr2:
3216 // 1,1,1,1,1,1,1,1,1,1,1,1
3217 // 1,1,1,1,1,1,1,1,1,1,1,1
3218 // 1,1,1,1,1,1,1,1,1,1,1,1
3219 // 1,1,1,1,1,1,1,1,1,1,1,1
3220 // 1,1,1,1,1,1,1,1,1,1,1,1
3221 // 1,1,1,1,1,1,1,1,1,1,1,1
3222 // 1,1,1,1,1,1,1,1,1,1,1,1
3223 // 1,1,1,1,1,1,1,1,1,1,1,1
3224 // 1,1,1,1,1,1,1,1,1,1,1,1
3225 // 1,1,1,1,1,1,1,1,1,1,1,1
3226 // 1,1,1,1,1,1,1,1,1,1,1,1
3227
3228 // X,Y = .
3229 // X+1,y = ^
3230 // X,Y+1 = *
3231 // X+1,Y+1 = #
3232
3233 // Filling in like this;
3234 // .*
3235 // ^#
3236 // 1st .
3237 // 2nd *
3238 // 3rd ^
3239 // 4th #
3240 // on single loop.
3241
3242 float[,] resultarr2 = new float[512, 512];
3243 for (int y = 0; y < WorldExtents.Y; y++)
3244 {
3245 for (int x = 0; x < WorldExtents.X; x++)
3246 {
3247 resultarr2[y * 2, x * 2] = resultarr[y, x];
3248
3249 if (y < WorldExtents.Y)
3250 {
3251 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3252 }
3253 if (x < WorldExtents.X)
3254 {
3255 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3256 }
3257 if (x < WorldExtents.X && y < WorldExtents.Y)
3258 {
3259 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3260 }
3261 }
3262 }
3263
3264 //Flatten out the array
3265 int i = 0;
3266 for (int y = 0; y < 512; y++)
3267 {
3268 for (int x = 0; x < 512; x++)
3269 {
3270 if (resultarr2[y, x] <= 0)
3271 returnarr[i] = 0.0000001f;
3272 else
3273 returnarr[i] = resultarr2[y, x];
3274
3275 i++;
3276 }
3277 }
3278
3279 return returnarr;
3280 }
3281
3282 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3283 {
3284 float[] returnarr = new float[262144];
3285 float[,] resultarr = new float[512,512];
3286
3287 // Filling out the array into its multi-dimensional components
3288 for (int y = 0; y < 256; y++)
3289 {
3290 for (int x = 0; x < 256; x++)
3291 {
3292 resultarr[y, x] = heightMap[y * 256 + x];
3293 }
3294 }
3295
3296 // Resize using interpolation
3297
3298 // This particular way is quick but it only works on a multiple of the original
3299
3300 // The idea behind this method can be described with the following diagrams
3301 // second pass and third pass happen in the same loop really.. just separated
3302 // them to show what this does.
3303
3304 // First Pass
3305 // ResultArr:
3306 // 1,1,1,1,1,1
3307 // 1,1,1,1,1,1
3308 // 1,1,1,1,1,1
3309 // 1,1,1,1,1,1
3310 // 1,1,1,1,1,1
3311 // 1,1,1,1,1,1
3312
3313 // Second Pass
3314 // ResultArr2:
3315 // 1,,1,,1,,1,,1,,1,
3316 // ,,,,,,,,,,
3317 // 1,,1,,1,,1,,1,,1,
3318 // ,,,,,,,,,,
3319 // 1,,1,,1,,1,,1,,1,
3320 // ,,,,,,,,,,
3321 // 1,,1,,1,,1,,1,,1,
3322 // ,,,,,,,,,,
3323 // 1,,1,,1,,1,,1,,1,
3324 // ,,,,,,,,,,
3325 // 1,,1,,1,,1,,1,,1,
3326
3327 // Third pass fills in the blanks
3328 // ResultArr2:
3329 // 1,1,1,1,1,1,1,1,1,1,1,1
3330 // 1,1,1,1,1,1,1,1,1,1,1,1
3331 // 1,1,1,1,1,1,1,1,1,1,1,1
3332 // 1,1,1,1,1,1,1,1,1,1,1,1
3333 // 1,1,1,1,1,1,1,1,1,1,1,1
3334 // 1,1,1,1,1,1,1,1,1,1,1,1
3335 // 1,1,1,1,1,1,1,1,1,1,1,1
3336 // 1,1,1,1,1,1,1,1,1,1,1,1
3337 // 1,1,1,1,1,1,1,1,1,1,1,1
3338 // 1,1,1,1,1,1,1,1,1,1,1,1
3339 // 1,1,1,1,1,1,1,1,1,1,1,1
3340
3341 // X,Y = .
3342 // X+1,y = ^
3343 // X,Y+1 = *
3344 // X+1,Y+1 = #
3345
3346 // Filling in like this;
3347 // .*
3348 // ^#
3349 // 1st .
3350 // 2nd *
3351 // 3rd ^
3352 // 4th #
3353 // on single loop.
3354
3355 float[,] resultarr2 = new float[512,512];
3356 for (int y = 0; y < (int)Constants.RegionSize; y++)
3357 {
3358 for (int x = 0; x < (int)Constants.RegionSize; x++)
3359 {
3360 resultarr2[y*2, x*2] = resultarr[y, x];
3361
3362 if (y < (int)Constants.RegionSize)
3363 {
3364 if (y + 1 < (int)Constants.RegionSize)
3365 {
3366 if (x + 1 < (int)Constants.RegionSize)
3367 {
3368 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3369 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3370 }
3371 else
3372 {
3373 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3374 }
3375 }
3376 else
3377 {
3378 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3379 }
3380 }
3381 if (x < (int)Constants.RegionSize)
3382 {
3383 if (x + 1 < (int)Constants.RegionSize)
3384 {
3385 if (y + 1 < (int)Constants.RegionSize)
3386 {
3387 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3388 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3389 }
3390 else
3391 {
3392 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3393 }
3394 }
3395 else
3396 {
3397 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3398 }
3399 }
3400 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3401 {
3402 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3403 {
3404 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3405 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3406 }
3407 else
3408 {
3409 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3410 }
3411 }
3412 }
3413 }
3414 //Flatten out the array
3415 int i = 0;
3416 for (int y = 0; y < 512; y++)
3417 {
3418 for (int x = 0; x < 512; x++)
3419 {
3420 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3421 {
3422 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3423 resultarr2[y, x] = 0;
3424 }
3425 returnarr[i] = resultarr2[y, x];
3426 i++;
3427 }
3428 }
3429
3430 return returnarr;
3431 }
3432
3433 #endregion
3434
3435 public override void SetTerrain(float[] heightMap)
3436 {
3437 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3438 {
3439 if (m_parentScene is OdeScene)
3440 {
3441 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3442 }
3443 }
3444 else
3445 {
3446 SetTerrain(heightMap, m_worldOffset);
3447 }
3448 }
3449
3450 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3451 {
3452 // this._heightmap[i] = (double)heightMap[i];
3453 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3454 //_origheightmap = heightMap;
3455
3456 float[] _heightmap;
3457
3458 // zero out a heightmap array float array (single dimension [flattened]))
3459 //if ((int)Constants.RegionSize == 256)
3460 // _heightmap = new float[514 * 514];
3461 //else
3462
3463 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3464
3465 uint heightmapWidth = Constants.RegionSize + 1;
3466 uint heightmapHeight = Constants.RegionSize + 1;
3467
3468 uint heightmapWidthSamples;
3469
3470 uint heightmapHeightSamples;
3471
3472 //if (((int)Constants.RegionSize) == 256)
3473 //{
3474 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3475 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3476 // heightmapWidth++;
3477 // heightmapHeight++;
3478 //}
3479 //else
3480 //{
3481
3482 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3483 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3484 //}
3485
3486 const float scale = 1.0f;
3487 const float offset = 0.0f;
3488 const float thickness = 0.2f;
3489 const int wrap = 0;
3490
3491 int regionsize = (int) Constants.RegionSize + 2;
3492 //Double resolution
3493 //if (((int)Constants.RegionSize) == 256)
3494 // heightMap = ResizeTerrain512Interpolation(heightMap);
3495
3496
3497 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3498 // regionsize = 512;
3499
3500 float hfmin = 2000;
3501 float hfmax = -2000;
3502
3503 for (int x = 0; x < heightmapWidthSamples; x++)
3504 {
3505 for (int y = 0; y < heightmapHeightSamples; y++)
3506 {
3507 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3508 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3509
3510
3511 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3512 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3513
3514 hfmin = (val < hfmin) ? val : hfmin;
3515 hfmax = (val > hfmax) ? val : hfmax;
3516 }
3517 }
3518
3519
3520
3521
3522 lock (OdeLock)
3523 {
3524 IntPtr GroundGeom = IntPtr.Zero;
3525 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3526 {
3527 RegionTerrain.Remove(pOffset);
3528 if (GroundGeom != IntPtr.Zero)
3529 {
3530 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3531 {
3532 TerrainHeightFieldHeights.Remove(GroundGeom);
3533 }
3534 d.SpaceRemove(space, GroundGeom);
3535 d.GeomDestroy(GroundGeom);
3536 }
3537
3538 }
3539 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3540 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3541 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3542 offset, thickness, wrap);
3543 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3544 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3545 if (GroundGeom != IntPtr.Zero)
3546 {
3547 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3548 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3549
3550 }
3551 geom_name_map[GroundGeom] = "Terrain";
3552
3553 d.Matrix3 R = new d.Matrix3();
3554
3555 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3556 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3557 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3558
3559 q1 = q1 * q2;
3560 //q1 = q1 * q3;
3561 Vector3 v3;
3562 float angle;
3563 q1.GetAxisAngle(out v3, out angle);
3564
3565 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3566 d.GeomSetRotation(GroundGeom, ref R);
3567 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)) - 1, (pOffset.Y + ((int)Constants.RegionSize * 0.5f)) - 1, 0);
3568 IntPtr testGround = IntPtr.Zero;
3569 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3570 {
3571 RegionTerrain.Remove(pOffset);
3572 }
3573 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3574 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3575
3576 }
3577 }
3578
3579 public override void DeleteTerrain()
3580 {
3581 }
3582
3583 public float GetWaterLevel()
3584 {
3585 return waterlevel;
3586 }
3587
3588 public override bool SupportsCombining()
3589 {
3590 return true;
3591 }
3592
3593 public override void UnCombine(PhysicsScene pScene)
3594 {
3595 IntPtr localGround = IntPtr.Zero;
3596// float[] localHeightfield;
3597 bool proceed = false;
3598 List<IntPtr> geomDestroyList = new List<IntPtr>();
3599
3600 lock (OdeLock)
3601 {
3602 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3603 {
3604 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3605 {
3606 if (geom == localGround)
3607 {
3608// localHeightfield = TerrainHeightFieldHeights[geom];
3609 proceed = true;
3610 }
3611 else
3612 {
3613 geomDestroyList.Add(geom);
3614 }
3615 }
3616
3617 if (proceed)
3618 {
3619 m_worldOffset = Vector3.Zero;
3620 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3621 m_parentScene = null;
3622
3623 foreach (IntPtr g in geomDestroyList)
3624 {
3625 // removingHeightField needs to be done or the garbage collector will
3626 // collect the terrain data before we tell ODE to destroy it causing
3627 // memory corruption
3628 if (TerrainHeightFieldHeights.ContainsKey(g))
3629 {
3630// float[] removingHeightField = TerrainHeightFieldHeights[g];
3631 TerrainHeightFieldHeights.Remove(g);
3632
3633 if (RegionTerrain.ContainsKey(g))
3634 {
3635 RegionTerrain.Remove(g);
3636 }
3637
3638 d.GeomDestroy(g);
3639 //removingHeightField = new float[0];
3640 }
3641 }
3642
3643 }
3644 else
3645 {
3646 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3647
3648 }
3649 }
3650 }
3651 }
3652
3653 public override void SetWaterLevel(float baseheight)
3654 {
3655 waterlevel = baseheight;
3656 randomizeWater(waterlevel);
3657 }
3658
3659 public void randomizeWater(float baseheight)
3660 {
3661 const uint heightmapWidth = m_regionWidth + 2;
3662 const uint heightmapHeight = m_regionHeight + 2;
3663 const uint heightmapWidthSamples = m_regionWidth + 2;
3664 const uint heightmapHeightSamples = m_regionHeight + 2;
3665 const float scale = 1.0f;
3666 const float offset = 0.0f;
3667 const float thickness = 2.9f;
3668 const int wrap = 0;
3669
3670 for (int i = 0; i < (258 * 258); i++)
3671 {
3672 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3673 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3674 }
3675
3676 lock (OdeLock)
3677 {
3678 if (WaterGeom != IntPtr.Zero)
3679 {
3680 d.SpaceRemove(space, WaterGeom);
3681 }
3682 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3683 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3684 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3685 offset, thickness, wrap);
3686 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3687 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3688 if (WaterGeom != IntPtr.Zero)
3689 {
3690 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3691 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3692
3693 }
3694 geom_name_map[WaterGeom] = "Water";
3695
3696 d.Matrix3 R = new d.Matrix3();
3697
3698 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3699 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3700 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3701
3702 q1 = q1 * q2;
3703 //q1 = q1 * q3;
3704 Vector3 v3;
3705 float angle;
3706 q1.GetAxisAngle(out v3, out angle);
3707
3708 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3709 d.GeomSetRotation(WaterGeom, ref R);
3710 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3711
3712 }
3713
3714 }
3715
3716 public override void Dispose()
3717 {
3718 m_rayCastManager.Dispose();
3719 m_rayCastManager = null;
3720
3721 lock (OdeLock)
3722 {
3723 lock (_prims)
3724 {
3725 foreach (OdePrim prm in _prims)
3726 {
3727 RemovePrim(prm);
3728 }
3729 }
3730
3731 //foreach (OdeCharacter act in _characters)
3732 //{
3733 //RemoveAvatar(act);
3734 //}
3735 d.WorldDestroy(world);
3736 //d.CloseODE();
3737 }
3738 }
3739 public override Dictionary<uint, float> GetTopColliders()
3740 {
3741 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3742 int cnt = 0;
3743 lock (_prims)
3744 {
3745 foreach (OdePrim prm in _prims)
3746 {
3747 if (prm.CollisionScore > 0)
3748 {
3749 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3750 cnt++;
3751 prm.CollisionScore = 0f;
3752 if (cnt > 25)
3753 {
3754 break;
3755 }
3756 }
3757 }
3758 }
3759 return returncolliders;
3760 }
3761
3762 public override bool SupportsRayCast()
3763 {
3764 return true;
3765 }
3766
3767 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3768 {
3769 if (retMethod != null)
3770 {
3771 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3772 }
3773 }
3774
3775#if USE_DRAWSTUFF
3776 // Keyboard callback
3777 public void command(int cmd)
3778 {
3779 IntPtr geom;
3780 d.Mass mass;
3781 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3782
3783
3784
3785 Char ch = Char.ToLower((Char)cmd);
3786 switch ((Char)ch)
3787 {
3788 case 'w':
3789 try
3790 {
3791 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3792
3793 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3794 ds.SetViewpoint(ref xyz, ref hpr);
3795 }
3796 catch (ArgumentException)
3797 { hpr.X = 0; }
3798 break;
3799
3800 case 'a':
3801 hpr.X++;
3802 ds.SetViewpoint(ref xyz, ref hpr);
3803 break;
3804
3805 case 's':
3806 try
3807 {
3808 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3809
3810 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3811 ds.SetViewpoint(ref xyz, ref hpr);
3812 }
3813 catch (ArgumentException)
3814 { hpr.X = 0; }
3815 break;
3816 case 'd':
3817 hpr.X--;
3818 ds.SetViewpoint(ref xyz, ref hpr);
3819 break;
3820 case 'r':
3821 xyz.Z++;
3822 ds.SetViewpoint(ref xyz, ref hpr);
3823 break;
3824 case 'f':
3825 xyz.Z--;
3826 ds.SetViewpoint(ref xyz, ref hpr);
3827 break;
3828 case 'e':
3829 xyz.Y++;
3830 ds.SetViewpoint(ref xyz, ref hpr);
3831 break;
3832 case 'q':
3833 xyz.Y--;
3834 ds.SetViewpoint(ref xyz, ref hpr);
3835 break;
3836 }
3837 }
3838
3839 public void step(int pause)
3840 {
3841
3842 ds.SetColor(1.0f, 1.0f, 0.0f);
3843 ds.SetTexture(ds.Texture.Wood);
3844 lock (_prims)
3845 {
3846 foreach (OdePrim prm in _prims)
3847 {
3848 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3849 if (prm.prim_geom != IntPtr.Zero)
3850 {
3851 d.Vector3 pos;
3852 d.GeomCopyPosition(prm.prim_geom, out pos);
3853 //d.BodyCopyPosition(body, out pos);
3854
3855 d.Matrix3 R;
3856 d.GeomCopyRotation(prm.prim_geom, out R);
3857 //d.BodyCopyRotation(body, out R);
3858
3859
3860 d.Vector3 sides = new d.Vector3();
3861 sides.X = prm.Size.X;
3862 sides.Y = prm.Size.Y;
3863 sides.Z = prm.Size.Z;
3864
3865 ds.DrawBox(ref pos, ref R, ref sides);
3866 }
3867 }
3868 }
3869 ds.SetColor(1.0f, 0.0f, 0.0f);
3870 lock (_characters)
3871 {
3872 foreach (OdeCharacter chr in _characters)
3873 {
3874 if (chr.Shell != IntPtr.Zero)
3875 {
3876 IntPtr body = d.GeomGetBody(chr.Shell);
3877
3878 d.Vector3 pos;
3879 d.GeomCopyPosition(chr.Shell, out pos);
3880 //d.BodyCopyPosition(body, out pos);
3881
3882 d.Matrix3 R;
3883 d.GeomCopyRotation(chr.Shell, out R);
3884 //d.BodyCopyRotation(body, out R);
3885
3886 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3887 d.Vector3 sides = new d.Vector3();
3888 sides.X = 0.5f;
3889 sides.Y = 0.5f;
3890 sides.Z = 0.5f;
3891
3892 ds.DrawBox(ref pos, ref R, ref sides);
3893 }
3894 }
3895 }
3896 }
3897
3898 public void start(int unused)
3899 {
3900 ds.SetViewpoint(ref xyz, ref hpr);
3901 }
3902#endif
3903 }
3904}
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
new file mode 100644
index 0000000..234af00
--- /dev/null
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -0,0 +1,3866 @@
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 USE_DRAWSTUFF
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 Ode.NET;
40#if USE_DRAWSTUFF
41using Drawstuff.NET;
42#endif
43using OpenSim.Framework;
44using OpenSim.Region.Physics.Manager;
45using OpenMetaverse;
46
47namespace OpenSim.Region.Physics.OdePlugin
48{
49 public enum StatusIndicators : int
50 {
51 Generic = 0,
52 Start = 1,
53 End = 2
54 }
55
56 public struct sCollisionData
57 {
58 public uint ColliderLocalId;
59 public uint CollidedWithLocalId;
60 public int NumberOfCollisions;
61 public int CollisionType;
62 public int StatusIndicator;
63 public int lastframe;
64 }
65
66 [Flags]
67 public enum CollisionCategories : int
68 {
69 Disabled = 0,
70 Geom = 0x00000001,
71 Body = 0x00000002,
72 Space = 0x00000004,
73 Character = 0x00000008,
74 Land = 0x00000010,
75 Water = 0x00000020,
76 Wind = 0x00000040,
77 Sensor = 0x00000080,
78 Selected = 0x00000100
79 }
80
81 /// <summary>
82 /// Material type for a primitive
83 /// </summary>
84 public enum Material : int
85 {
86 /// <summary></summary>
87 Stone = 0,
88 /// <summary></summary>
89 Metal = 1,
90 /// <summary></summary>
91 Glass = 2,
92 /// <summary></summary>
93 Wood = 3,
94 /// <summary></summary>
95 Flesh = 4,
96 /// <summary></summary>
97 Plastic = 5,
98 /// <summary></summary>
99 Rubber = 6
100 }
101
102 public sealed class OdeScene : PhysicsScene
103 {
104 private readonly ILog m_log;
105 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
106
107 CollisionLocker ode;
108
109 private Random fluidRandomizer = new Random(Environment.TickCount);
110
111 private const uint m_regionWidth = Constants.RegionSize;
112 private const uint m_regionHeight = Constants.RegionSize;
113
114 private float ODE_STEPSIZE = 0.020f;
115 private float metersInSpace = 29.9f;
116 private float m_timeDilation = 1.0f;
117
118 public float gravityx = 0f;
119 public float gravityy = 0f;
120 public float gravityz = -9.8f;
121
122 private float contactsurfacelayer = 0.001f;
123
124 private int worldHashspaceLow = -4;
125 private int worldHashspaceHigh = 128;
126
127 private int smallHashspaceLow = -4;
128 private int smallHashspaceHigh = 66;
129
130 private float waterlevel = 0f;
131 private int framecount = 0;
132 //private int m_returncollisions = 10;
133
134 private readonly IntPtr contactgroup;
135
136 internal IntPtr LandGeom;
137 internal IntPtr WaterGeom;
138
139 private float nmTerrainContactFriction = 255.0f;
140 private float nmTerrainContactBounce = 0.1f;
141 private float nmTerrainContactERP = 0.1025f;
142
143 private float mTerrainContactFriction = 75f;
144 private float mTerrainContactBounce = 0.1f;
145 private float mTerrainContactERP = 0.05025f;
146
147 private float nmAvatarObjectContactFriction = 250f;
148 private float nmAvatarObjectContactBounce = 0.1f;
149
150 private float mAvatarObjectContactFriction = 75f;
151 private float mAvatarObjectContactBounce = 0.1f;
152
153 private float avPIDD = 3200f;
154 private float avPIDP = 1400f;
155 private float avCapRadius = 0.37f;
156 private float avStandupTensor = 2000000f;
157 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
158 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
159 private float avDensity = 80f;
160 private float avHeightFudgeFactor = 0.52f;
161 private float avMovementDivisorWalk = 1.3f;
162 private float avMovementDivisorRun = 0.8f;
163 private float minimumGroundFlightOffset = 3f;
164 public float maximumMassObject = 10000.01f;
165
166 public bool meshSculptedPrim = true;
167 public bool forceSimplePrimMeshing = false;
168
169 public float meshSculptLOD = 32;
170 public float MeshSculptphysicalLOD = 16;
171
172 public float geomDefaultDensity = 10.000006836f;
173
174 public int geomContactPointsStartthrottle = 3;
175 public int geomUpdatesPerThrottledUpdate = 15;
176
177 public float bodyPIDD = 35f;
178 public float bodyPIDG = 25;
179
180 public int geomCrossingFailuresBeforeOutofbounds = 5;
181
182 public float bodyMotorJointMaxforceTensor = 2;
183
184 public int bodyFramesAutoDisable = 20;
185
186 private float[] _watermap;
187 private bool m_filterCollisions = true;
188
189 private d.NearCallback nearCallback;
190 public d.TriCallback triCallback;
191 public d.TriArrayCallback triArrayCallback;
192 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
193 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
194 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
195 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
196 private readonly Object _taintedPrimLock = new Object();
197 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
198 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
199 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
200 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
201 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
202 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
203 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
204 private bool m_NINJA_physics_joints_enabled = false;
205 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
206 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
207 private d.ContactGeom[] contacts;
208 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
209 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
210 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
211 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
212 private Object externalJointRequestsLock = new Object();
213 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
214 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
215 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
216 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
217
218 private d.Contact contact;
219 private d.Contact TerrainContact;
220 private d.Contact AvatarMovementprimContact;
221 private d.Contact AvatarMovementTerrainContact;
222 private d.Contact WaterContact;
223 private d.Contact[,] m_materialContacts;
224
225//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
226//Ckrinke private int m_randomizeWater = 200;
227 private int m_physicsiterations = 10;
228 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
229 private readonly PhysicsActor PANull = new NullPhysicsActor();
230 private float step_time = 0.0f;
231//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
232//Ckrinke private int ms = 0;
233 public IntPtr world;
234 //private bool returncollisions = false;
235 // private uint obj1LocalID = 0;
236 private uint obj2LocalID = 0;
237 //private int ctype = 0;
238 private OdeCharacter cc1;
239 private OdePrim cp1;
240 private OdeCharacter cc2;
241 private OdePrim cp2;
242 private int tickCountFrameRun;
243
244 private int latertickcount=0;
245 //private int cStartStop = 0;
246 //private string cDictKey = "";
247
248 public IntPtr space;
249
250 //private IntPtr tmpSpace;
251 // split static geometry collision handling into spaces of 30 meters
252 public IntPtr[,] staticPrimspace;
253
254 public Object OdeLock;
255
256 public IMesher mesher;
257
258 private IConfigSource m_config;
259
260 public bool physics_logging = false;
261 public int physics_logging_interval = 0;
262 public bool physics_logging_append_existing_logfile = false;
263
264 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
265 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
266
267 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
268 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
269 // TODO: unused: private uint heightmapWidthSamples;
270 // TODO: unused: private uint heightmapHeightSamples;
271
272 private volatile int m_global_contactcount = 0;
273
274 private Vector3 m_worldOffset = Vector3.Zero;
275 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
276 private PhysicsScene m_parentScene = null;
277
278 private ODERayCastRequestManager m_rayCastManager;
279
280 /// <summary>
281 /// Initiailizes the scene
282 /// Sets many properties that ODE requires to be stable
283 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
284 /// </summary>
285 public OdeScene(CollisionLocker dode, string sceneIdentifier)
286 {
287 m_log
288 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
289
290 OdeLock = new Object();
291 ode = dode;
292 nearCallback = near;
293 triCallback = TriCallback;
294 triArrayCallback = TriArrayCallback;
295 m_rayCastManager = new ODERayCastRequestManager(this);
296 lock (OdeLock)
297 {
298 // Create the world and the first space
299 world = d.WorldCreate();
300 space = d.HashSpaceCreate(IntPtr.Zero);
301
302
303 contactgroup = d.JointGroupCreate(0);
304 //contactgroup
305
306 d.WorldSetAutoDisableFlag(world, false);
307 #if USE_DRAWSTUFF
308
309 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
310 viewthread.Start();
311 #endif
312 }
313
314
315 _watermap = new float[258 * 258];
316
317 // Zero out the prim spaces array (we split our space into smaller spaces so
318 // we can hit test less.
319 }
320
321#if USE_DRAWSTUFF
322 public void startvisualization(object o)
323 {
324 ds.Functions fn;
325 fn.version = ds.VERSION;
326 fn.start = new ds.CallbackFunction(start);
327 fn.step = new ds.CallbackFunction(step);
328 fn.command = new ds.CallbackFunction(command);
329 fn.stop = null;
330 fn.path_to_textures = "./textures";
331 string[] args = new string[0];
332 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
333 }
334#endif
335
336 // Initialize the mesh plugin
337 public override void Initialise(IMesher meshmerizer, IConfigSource config)
338 {
339 mesher = meshmerizer;
340 m_config = config;
341 // Defaults
342
343 if (Environment.OSVersion.Platform == PlatformID.Unix)
344 {
345 avPIDD = 3200.0f;
346 avPIDP = 1400.0f;
347 avStandupTensor = 2000000f;
348 }
349 else
350 {
351 avPIDD = 2200.0f;
352 avPIDP = 900.0f;
353 avStandupTensor = 550000f;
354 }
355
356 int contactsPerCollision = 80;
357
358 if (m_config != null)
359 {
360 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
361 if (physicsconfig != null)
362 {
363 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
364 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
365 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
366
367 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
368 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
369
370 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
371 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
372 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
373
374 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
375
376 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
377 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
378 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
379
380 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
381 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
382 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
383
384 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
385 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
386
387 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
388 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
389
390 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
391 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
392
393 avDensity = physicsconfig.GetFloat("av_density", 80f);
394 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
395 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
396 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
397 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
398 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
399
400 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
401
402 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
403 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
404 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
405
406 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
407 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
408
409 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
410 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
411
412 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
413 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
414 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
415 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
416 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
417
418 if (Environment.OSVersion.Platform == PlatformID.Unix)
419 {
420 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
421 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
422 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
423 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
424 }
425 else
426 {
427 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
428 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
429 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
430 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
431 }
432
433 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
434 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
435 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
436
437 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
438 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
439 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
440 }
441 }
442
443 contacts = new d.ContactGeom[contactsPerCollision];
444
445 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
446
447 // Centeral contact friction and bounce
448 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
449 // an avatar falls through in Z but not in X or Y when walking on a prim.
450 contact.surface.mode |= d.ContactFlags.SoftERP;
451 contact.surface.mu = nmAvatarObjectContactFriction;
452 contact.surface.bounce = nmAvatarObjectContactBounce;
453 contact.surface.soft_cfm = 0.010f;
454 contact.surface.soft_erp = 0.010f;
455
456 // Terrain contact friction and Bounce
457 // This is the *non* moving version. Use this when an avatar
458 // isn't moving to keep it in place better
459 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
460 TerrainContact.surface.mu = nmTerrainContactFriction;
461 TerrainContact.surface.bounce = nmTerrainContactBounce;
462 TerrainContact.surface.soft_erp = nmTerrainContactERP;
463
464 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
465 WaterContact.surface.mu = 0f; // No friction
466 WaterContact.surface.bounce = 0.0f; // No bounce
467 WaterContact.surface.soft_cfm = 0.010f;
468 WaterContact.surface.soft_erp = 0.010f;
469
470 // Prim contact friction and bounce
471 // THis is the *non* moving version of friction and bounce
472 // Use this when an avatar comes in contact with a prim
473 // and is moving
474 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
475 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
476
477 // Terrain contact friction bounce and various error correcting calculations
478 // Use this when an avatar is in contact with the terrain and moving.
479 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
480 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
481 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
482 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
483
484 /*
485 <summary></summary>
486 Stone = 0,
487 /// <summary></summary>
488 Metal = 1,
489 /// <summary></summary>
490 Glass = 2,
491 /// <summary></summary>
492 Wood = 3,
493 /// <summary></summary>
494 Flesh = 4,
495 /// <summary></summary>
496 Plastic = 5,
497 /// <summary></summary>
498 Rubber = 6
499 */
500
501 m_materialContacts = new d.Contact[7,2];
502
503 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
504 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
505 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
506 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
507 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
508 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
509
510 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
511 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
512 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
513 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
514 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
515 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
516
517 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
518 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
519 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
520 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
521 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
522 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
523
524 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
525 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
526 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
527 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
528 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
529 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
530
531 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
532 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
533 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
534 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
535 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
536 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
537
538 /*
539 private float nmAvatarObjectContactFriction = 250f;
540 private float nmAvatarObjectContactBounce = 0.1f;
541
542 private float mAvatarObjectContactFriction = 75f;
543 private float mAvatarObjectContactBounce = 0.1f;
544 */
545 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
546 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
547 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
548 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
549 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
550 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
551
552 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
553 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
554 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
555 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
556 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
557 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
558
559 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
560 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
561 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
562 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
563 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
564 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
565
566 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
567 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
568 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
569 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
570 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
571 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
572
573 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
574 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
575 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
576 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
577 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
578 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
579
580 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
581 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
582 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
583 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
584 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
585 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
586
587 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
588 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
589 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
590 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
591 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
592 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
593
594 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
595 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
596 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
597 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
598 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
599 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
600
601 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
602 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
603 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
604 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
605 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
606 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
607
608 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
609
610 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
611
612 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
613 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
614
615 d.WorldSetLinearDamping(world, 256f);
616 d.WorldSetAngularDamping(world, 256f);
617 d.WorldSetAngularDampingThreshold(world, 256f);
618 d.WorldSetLinearDampingThreshold(world, 256f);
619 d.WorldSetMaxAngularSpeed(world, 256f);
620
621 // Set how many steps we go without running collision testing
622 // This is in addition to the step size.
623 // Essentially Steps * m_physicsiterations
624 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
625 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
626
627 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
628 {
629 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
630 {
631 staticPrimspace[i, j] = IntPtr.Zero;
632 }
633 }
634 }
635
636 internal void waitForSpaceUnlock(IntPtr space)
637 {
638 //if (space != IntPtr.Zero)
639 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
640 }
641
642 /// <summary>
643 /// Debug space message for printing the space that a prim/avatar is in.
644 /// </summary>
645 /// <param name="pos"></param>
646 /// <returns>Returns which split up space the given position is in.</returns>
647 public string whichspaceamIin(Vector3 pos)
648 {
649 return calculateSpaceForGeom(pos).ToString();
650 }
651
652 #region Collision Detection
653
654 /// <summary>
655 /// This is our near callback. A geometry is near a body
656 /// </summary>
657 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
658 /// <param name="g1">a geometry or space</param>
659 /// <param name="g2">another geometry or space</param>
660 private void near(IntPtr space, IntPtr g1, IntPtr g2)
661 {
662 // no lock here! It's invoked from within Simulate(), which is thread-locked
663
664 // Test if we're colliding a geom with a space.
665 // If so we have to drill down into the space recursively
666
667 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
668 {
669 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
670 return;
671
672 // Separating static prim geometry spaces.
673 // We'll be calling near recursivly if one
674 // of them is a space to find all of the
675 // contact points in the space
676 try
677 {
678 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
679 }
680 catch (AccessViolationException)
681 {
682 m_log.Warn("[PHYSICS]: Unable to collide test a space");
683 return;
684 }
685 //Colliding a space or a geom with a space or a geom. so drill down
686
687 //Collide all geoms in each space..
688 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
689 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
690 return;
691 }
692
693 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
694 return;
695
696 IntPtr b1 = d.GeomGetBody(g1);
697 IntPtr b2 = d.GeomGetBody(g2);
698
699 // d.GeomClassID id = d.GeomGetClass(g1);
700
701 String name1 = null;
702 String name2 = null;
703
704 if (!geom_name_map.TryGetValue(g1, out name1))
705 {
706 name1 = "null";
707 }
708 if (!geom_name_map.TryGetValue(g2, out name2))
709 {
710 name2 = "null";
711 }
712
713 //if (id == d.GeomClassId.TriMeshClass)
714 //{
715 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
716 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
717 //}
718
719 // Figure out how many contact points we have
720 int count = 0;
721 try
722 {
723 // Colliding Geom To Geom
724 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
725
726 if (g1 == g2)
727 return; // Can't collide with yourself
728
729 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
730 return;
731
732 lock (contacts)
733 {
734 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
735 if (count > contacts.Length)
736 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
737 }
738 }
739 catch (SEHException)
740 {
741 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.");
742 ode.drelease(world);
743 base.TriggerPhysicsBasedRestart();
744 }
745 catch (Exception e)
746 {
747 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
748 return;
749 }
750
751 PhysicsActor p1;
752 PhysicsActor p2;
753
754 if (!actor_name_map.TryGetValue(g1, out p1))
755 {
756 p1 = PANull;
757 }
758
759 if (!actor_name_map.TryGetValue(g2, out p2))
760 {
761 p2 = PANull;
762 }
763
764 ContactPoint maxDepthContact = new ContactPoint();
765 if (p1.CollisionScore + count >= float.MaxValue)
766 p1.CollisionScore = 0;
767 p1.CollisionScore += count;
768
769 if (p2.CollisionScore + count >= float.MaxValue)
770 p2.CollisionScore = 0;
771 p2.CollisionScore += count;
772
773 for (int i = 0; i < count; i++)
774 {
775 d.ContactGeom curContact = contacts[i];
776
777 if (curContact.depth > maxDepthContact.PenetrationDepth)
778 {
779 maxDepthContact = new ContactPoint(
780 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
781 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
782 curContact.depth
783 );
784 }
785
786 //m_log.Warn("[CCOUNT]: " + count);
787 IntPtr joint;
788 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
789 // allows us to have different settings
790
791 // We only need to test p2 for 'jump crouch purposes'
792 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
793 {
794 // Testing if the collision is at the feet of the avatar
795
796 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
797 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
798 p2.IsColliding = true;
799 }
800 else
801 {
802 p2.IsColliding = true;
803 }
804
805 //if ((framecount % m_returncollisions) == 0)
806
807 switch (p1.PhysicsActorType)
808 {
809 case (int)ActorTypes.Agent:
810 p2.CollidingObj = true;
811 break;
812 case (int)ActorTypes.Prim:
813 if (p2.Velocity.LengthSquared() > 0.0f)
814 p2.CollidingObj = true;
815 break;
816 case (int)ActorTypes.Unknown:
817 p2.CollidingGround = true;
818 break;
819 default:
820 p2.CollidingGround = true;
821 break;
822 }
823
824 // we don't want prim or avatar to explode
825
826 #region InterPenetration Handling - Unintended physics explosions
827# region disabled code1
828
829 if (curContact.depth >= 0.08f)
830 {
831 //This is disabled at the moment only because it needs more tweaking
832 //It will eventually be uncommented
833 /*
834 if (contact.depth >= 1.00f)
835 {
836 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
837 }
838
839 //If you interpenetrate a prim with an agent
840 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
841 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
842 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
843 p2.PhysicsActorType == (int) ActorTypes.Prim))
844 {
845
846 //contact.depth = contact.depth * 4.15f;
847 /*
848 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
849 {
850 p2.CollidingObj = true;
851 contact.depth = 0.003f;
852 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
853 OdeCharacter character = (OdeCharacter) p2;
854 character.SetPidStatus(true);
855 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
856
857 }
858 else
859 {
860
861 //contact.depth = 0.0000000f;
862 }
863 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
864 {
865
866 p1.CollidingObj = true;
867 contact.depth = 0.003f;
868 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
869 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
870 OdeCharacter character = (OdeCharacter)p1;
871 character.SetPidStatus(true);
872 }
873 else
874 {
875
876 //contact.depth = 0.0000000f;
877 }
878
879
880
881 }
882*/
883 // If you interpenetrate a prim with another prim
884 /*
885 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
886 {
887 #region disabledcode2
888 //OdePrim op1 = (OdePrim)p1;
889 //OdePrim op2 = (OdePrim)p2;
890 //op1.m_collisionscore++;
891 //op2.m_collisionscore++;
892
893 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
894 //{
895 //op1.m_taintdisable = true;
896 //AddPhysicsActorTaint(p1);
897 //op2.m_taintdisable = true;
898 //AddPhysicsActorTaint(p2);
899 //}
900
901 //if (contact.depth >= 0.25f)
902 //{
903 // Don't collide, one or both prim will expld.
904
905 //op1.m_interpenetrationcount++;
906 //op2.m_interpenetrationcount++;
907 //interpenetrations_before_disable = 200;
908 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
909 //{
910 //op1.m_taintdisable = true;
911 //AddPhysicsActorTaint(p1);
912 //}
913 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
914 //{
915 // op2.m_taintdisable = true;
916 //AddPhysicsActorTaint(p2);
917 //}
918
919 //contact.depth = contact.depth / 8f;
920 //contact.normal = new d.Vector3(0, 0, 1);
921 //}
922 //if (op1.m_disabled || op2.m_disabled)
923 //{
924 //Manually disabled objects stay disabled
925 //contact.depth = 0f;
926 //}
927 #endregion
928 }
929 */
930#endregion
931 if (curContact.depth >= 1.00f)
932 {
933 //m_log.Info("[P]: " + contact.depth.ToString());
934 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
935 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
936 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
937 p2.PhysicsActorType == (int) ActorTypes.Unknown))
938 {
939 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
940 {
941 if (p2 is OdeCharacter)
942 {
943 OdeCharacter character = (OdeCharacter) p2;
944
945 //p2.CollidingObj = true;
946 curContact.depth = 0.00000003f;
947 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
948 curContact.pos =
949 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
950 curContact.pos.Y + (p1.Size.Y/2),
951 curContact.pos.Z + (p1.Size.Z/2));
952 character.SetPidStatus(true);
953 }
954 }
955
956
957 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
958 {
959 if (p1 is OdeCharacter)
960 {
961 OdeCharacter character = (OdeCharacter) p1;
962
963 //p2.CollidingObj = true;
964 curContact.depth = 0.00000003f;
965 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
966 curContact.pos =
967 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
968 curContact.pos.Y + (p1.Size.Y/2),
969 curContact.pos.Z + (p1.Size.Z/2));
970 character.SetPidStatus(true);
971 }
972 }
973 }
974 }
975 }
976
977 #endregion
978
979 // Logic for collision handling
980 // Note, that if *all* contacts are skipped (VolumeDetect)
981 // The prim still detects (and forwards) collision events but
982 // appears to be phantom for the world
983 Boolean skipThisContact = false;
984
985 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
986 skipThisContact = true; // No collision on volume detect prims
987
988 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
989 skipThisContact = true; // No collision on volume detect prims
990
991 if (!skipThisContact && curContact.depth < 0f)
992 skipThisContact = true;
993
994 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
995 skipThisContact = true;
996
997 const int maxContactsbeforedeath = 4000;
998 joint = IntPtr.Zero;
999
1000 if (!skipThisContact)
1001 {
1002 // If we're colliding against terrain
1003 if (name1 == "Terrain" || name2 == "Terrain")
1004 {
1005 // If we're moving
1006 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1007 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1008 {
1009 // Use the movement terrain contact
1010 AvatarMovementTerrainContact.geom = curContact;
1011 _perloopContact.Add(curContact);
1012 if (m_global_contactcount < maxContactsbeforedeath)
1013 {
1014 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1015 m_global_contactcount++;
1016 }
1017 }
1018 else
1019 {
1020 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1021 {
1022 // Use the non moving terrain contact
1023 TerrainContact.geom = curContact;
1024 _perloopContact.Add(curContact);
1025 if (m_global_contactcount < maxContactsbeforedeath)
1026 {
1027 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1028 m_global_contactcount++;
1029 }
1030 }
1031 else
1032 {
1033 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1034 {
1035 // prim prim contact
1036 // int pj294950 = 0;
1037 int movintYN = 0;
1038 int material = (int) Material.Wood;
1039 // prim terrain contact
1040 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1041 {
1042 movintYN = 1;
1043 }
1044
1045 if (p2 is OdePrim)
1046 material = ((OdePrim)p2).m_material;
1047
1048 //m_log.DebugFormat("Material: {0}", material);
1049 m_materialContacts[material, movintYN].geom = curContact;
1050 _perloopContact.Add(curContact);
1051
1052 if (m_global_contactcount < maxContactsbeforedeath)
1053 {
1054 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1055 m_global_contactcount++;
1056
1057 }
1058
1059 }
1060 else
1061 {
1062 int movintYN = 0;
1063 // prim terrain contact
1064 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1065 {
1066 movintYN = 1;
1067 }
1068
1069 int material = (int)Material.Wood;
1070
1071 if (p2 is OdePrim)
1072 material = ((OdePrim)p2).m_material;
1073 //m_log.DebugFormat("Material: {0}", material);
1074 m_materialContacts[material, movintYN].geom = curContact;
1075 _perloopContact.Add(curContact);
1076
1077 if (m_global_contactcount < maxContactsbeforedeath)
1078 {
1079 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1080 m_global_contactcount++;
1081
1082 }
1083 }
1084 }
1085 }
1086 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1087 //{
1088 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1089 //}
1090 }
1091 else if (name1 == "Water" || name2 == "Water")
1092 {
1093 /*
1094 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1095 {
1096 }
1097 else
1098 {
1099 }
1100 */
1101 //WaterContact.surface.soft_cfm = 0.0000f;
1102 //WaterContact.surface.soft_erp = 0.00000f;
1103 if (curContact.depth > 0.1f)
1104 {
1105 curContact.depth *= 52;
1106 //contact.normal = new d.Vector3(0, 0, 1);
1107 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1108 }
1109 WaterContact.geom = curContact;
1110 _perloopContact.Add(curContact);
1111 if (m_global_contactcount < maxContactsbeforedeath)
1112 {
1113 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1114 m_global_contactcount++;
1115 }
1116 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1117 }
1118 else
1119 {
1120 // we're colliding with prim or avatar
1121 // check if we're moving
1122 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1123 {
1124 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1125 {
1126 // Use the Movement prim contact
1127 AvatarMovementprimContact.geom = curContact;
1128 _perloopContact.Add(curContact);
1129 if (m_global_contactcount < maxContactsbeforedeath)
1130 {
1131 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1132 m_global_contactcount++;
1133 }
1134 }
1135 else
1136 {
1137 // Use the non movement contact
1138 contact.geom = curContact;
1139 _perloopContact.Add(curContact);
1140
1141 if (m_global_contactcount < maxContactsbeforedeath)
1142 {
1143 joint = d.JointCreateContact(world, contactgroup, ref contact);
1144 m_global_contactcount++;
1145 }
1146 }
1147 }
1148 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1149 {
1150 //p1.PhysicsActorType
1151 int material = (int)Material.Wood;
1152
1153 if (p2 is OdePrim)
1154 material = ((OdePrim)p2).m_material;
1155
1156 //m_log.DebugFormat("Material: {0}", material);
1157 m_materialContacts[material, 0].geom = curContact;
1158 _perloopContact.Add(curContact);
1159
1160 if (m_global_contactcount < maxContactsbeforedeath)
1161 {
1162 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1163 m_global_contactcount++;
1164
1165 }
1166 }
1167 }
1168
1169 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1170 {
1171 d.JointAttach(joint, b1, b2);
1172 m_global_contactcount++;
1173 }
1174 }
1175
1176 collision_accounting_events(p1, p2, maxDepthContact);
1177
1178 if (count > geomContactPointsStartthrottle)
1179 {
1180 // If there are more then 3 contact points, it's likely
1181 // that we've got a pile of objects, so ...
1182 // We don't want to send out hundreds of terse updates over and over again
1183 // so lets throttle them and send them again after it's somewhat sorted out.
1184 p2.ThrottleUpdates = true;
1185 }
1186 //m_log.Debug(count.ToString());
1187 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1188 }
1189 }
1190
1191 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1192 {
1193 bool result = false;
1194 //return result;
1195 if (!m_filterCollisions)
1196 return false;
1197
1198 ActorTypes at = (ActorTypes)atype;
1199 lock (_perloopContact)
1200 {
1201 foreach (d.ContactGeom contact in _perloopContact)
1202 {
1203 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1204 //{
1205 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1206 if (at == ActorTypes.Agent)
1207 {
1208 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1209 {
1210
1211 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1212 {
1213 //contactGeom.depth *= .00005f;
1214 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1215 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1216 result = true;
1217 break;
1218 }
1219 else
1220 {
1221 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1222 }
1223 }
1224 else
1225 {
1226 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1227 //int i = 0;
1228 }
1229 }
1230 else if (at == ActorTypes.Prim)
1231 {
1232 //d.AABB aabb1 = new d.AABB();
1233 //d.AABB aabb2 = new d.AABB();
1234
1235 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1236 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1237 //aabb1.
1238 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1239 {
1240 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1241 {
1242 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1243 {
1244 result = true;
1245 break;
1246 }
1247 }
1248 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1249 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1250 }
1251
1252 }
1253
1254 //}
1255
1256 }
1257 }
1258
1259 return result;
1260 }
1261
1262 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1263 {
1264 // obj1LocalID = 0;
1265 //returncollisions = false;
1266 obj2LocalID = 0;
1267 //ctype = 0;
1268 //cStartStop = 0;
1269 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1270 return;
1271
1272 switch ((ActorTypes)p2.PhysicsActorType)
1273 {
1274 case ActorTypes.Agent:
1275 cc2 = (OdeCharacter)p2;
1276
1277 // obj1LocalID = cc2.m_localID;
1278 switch ((ActorTypes)p1.PhysicsActorType)
1279 {
1280 case ActorTypes.Agent:
1281 cc1 = (OdeCharacter)p1;
1282 obj2LocalID = cc1.m_localID;
1283 cc1.AddCollisionEvent(cc2.m_localID, contact);
1284 //ctype = (int)CollisionCategories.Character;
1285
1286 //if (cc1.CollidingObj)
1287 //cStartStop = (int)StatusIndicators.Generic;
1288 //else
1289 //cStartStop = (int)StatusIndicators.Start;
1290
1291 //returncollisions = true;
1292 break;
1293 case ActorTypes.Prim:
1294 if (p1 is OdePrim)
1295 {
1296 cp1 = (OdePrim) p1;
1297 obj2LocalID = cp1.m_localID;
1298 cp1.AddCollisionEvent(cc2.m_localID, contact);
1299 }
1300 //ctype = (int)CollisionCategories.Geom;
1301
1302 //if (cp1.CollidingObj)
1303 //cStartStop = (int)StatusIndicators.Generic;
1304 //else
1305 //cStartStop = (int)StatusIndicators.Start;
1306
1307 //returncollisions = true;
1308 break;
1309
1310 case ActorTypes.Ground:
1311 case ActorTypes.Unknown:
1312 obj2LocalID = 0;
1313 //ctype = (int)CollisionCategories.Land;
1314 //returncollisions = true;
1315 break;
1316 }
1317
1318 cc2.AddCollisionEvent(obj2LocalID, contact);
1319 break;
1320 case ActorTypes.Prim:
1321
1322 if (p2 is OdePrim)
1323 {
1324 cp2 = (OdePrim) p2;
1325
1326 // obj1LocalID = cp2.m_localID;
1327 switch ((ActorTypes) p1.PhysicsActorType)
1328 {
1329 case ActorTypes.Agent:
1330 if (p1 is OdeCharacter)
1331 {
1332 cc1 = (OdeCharacter) p1;
1333 obj2LocalID = cc1.m_localID;
1334 cc1.AddCollisionEvent(cp2.m_localID, contact);
1335 //ctype = (int)CollisionCategories.Character;
1336
1337 //if (cc1.CollidingObj)
1338 //cStartStop = (int)StatusIndicators.Generic;
1339 //else
1340 //cStartStop = (int)StatusIndicators.Start;
1341 //returncollisions = true;
1342 }
1343 break;
1344 case ActorTypes.Prim:
1345
1346 if (p1 is OdePrim)
1347 {
1348 cp1 = (OdePrim) p1;
1349 obj2LocalID = cp1.m_localID;
1350 cp1.AddCollisionEvent(cp2.m_localID, contact);
1351 //ctype = (int)CollisionCategories.Geom;
1352
1353 //if (cp1.CollidingObj)
1354 //cStartStop = (int)StatusIndicators.Generic;
1355 //else
1356 //cStartStop = (int)StatusIndicators.Start;
1357
1358 //returncollisions = true;
1359 }
1360 break;
1361
1362 case ActorTypes.Ground:
1363 case ActorTypes.Unknown:
1364 obj2LocalID = 0;
1365 //ctype = (int)CollisionCategories.Land;
1366
1367 //returncollisions = true;
1368 break;
1369 }
1370
1371 cp2.AddCollisionEvent(obj2LocalID, contact);
1372 }
1373 break;
1374 }
1375 //if (returncollisions)
1376 //{
1377
1378 //lock (m_storedCollisions)
1379 //{
1380 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1381 //if (m_storedCollisions.ContainsKey(cDictKey))
1382 //{
1383 //sCollisionData objd = m_storedCollisions[cDictKey];
1384 //objd.NumberOfCollisions += 1;
1385 //objd.lastframe = framecount;
1386 //m_storedCollisions[cDictKey] = objd;
1387 //}
1388 //else
1389 //{
1390 //sCollisionData objd = new sCollisionData();
1391 //objd.ColliderLocalId = obj1LocalID;
1392 //objd.CollidedWithLocalId = obj2LocalID;
1393 //objd.CollisionType = ctype;
1394 //objd.NumberOfCollisions = 1;
1395 //objd.lastframe = framecount;
1396 //objd.StatusIndicator = cStartStop;
1397 //m_storedCollisions.Add(cDictKey, objd);
1398 //}
1399 //}
1400 // }
1401 }
1402
1403 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1404 {
1405 /* String name1 = null;
1406 String name2 = null;
1407
1408 if (!geom_name_map.TryGetValue(trimesh, out name1))
1409 {
1410 name1 = "null";
1411 }
1412 if (!geom_name_map.TryGetValue(refObject, out name2))
1413 {
1414 name2 = "null";
1415 }
1416
1417 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1418 */
1419 return 1;
1420 }
1421
1422 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1423 {
1424 String name1 = null;
1425 String name2 = null;
1426
1427 if (!geom_name_map.TryGetValue(trimesh, out name1))
1428 {
1429 name1 = "null";
1430 }
1431
1432 if (!geom_name_map.TryGetValue(refObject, out name2))
1433 {
1434 name2 = "null";
1435 }
1436
1437 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1438
1439 d.Vector3 v0 = new d.Vector3();
1440 d.Vector3 v1 = new d.Vector3();
1441 d.Vector3 v2 = new d.Vector3();
1442
1443 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1444 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1445
1446 return 1;
1447 }
1448
1449 /// <summary>
1450 /// This is our collision testing routine in ODE
1451 /// </summary>
1452 /// <param name="timeStep"></param>
1453 private void collision_optimized(float timeStep)
1454 {
1455 _perloopContact.Clear();
1456
1457 lock (_characters)
1458 {
1459 foreach (OdeCharacter chr in _characters)
1460 {
1461 // Reset the collision values to false
1462 // since we don't know if we're colliding yet
1463
1464 // For some reason this can happen. Don't ask...
1465 //
1466 if (chr == null)
1467 continue;
1468
1469 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1470 continue;
1471
1472 chr.IsColliding = false;
1473 chr.CollidingGround = false;
1474 chr.CollidingObj = false;
1475
1476 // test the avatar's geometry for collision with the space
1477 // This will return near and the space that they are the closest to
1478 // And we'll run this again against the avatar and the space segment
1479 // This will return with a bunch of possible objects in the space segment
1480 // and we'll run it again on all of them.
1481 try
1482 {
1483 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1484 }
1485 catch (AccessViolationException)
1486 {
1487 m_log.Warn("[PHYSICS]: Unable to space collide");
1488 }
1489 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1490 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1491 //{
1492 //chr.Position.Z = terrainheight + 10.0f;
1493 //forcedZ = true;
1494 //}
1495 }
1496 }
1497
1498 lock (_activeprims)
1499 {
1500 List<OdePrim> removeprims = null;
1501 foreach (OdePrim chr in _activeprims)
1502 {
1503 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1504 {
1505 try
1506 {
1507 lock (chr)
1508 {
1509 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1510 {
1511 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1512 }
1513 else
1514 {
1515 if (removeprims == null)
1516 {
1517 removeprims = new List<OdePrim>();
1518 }
1519 removeprims.Add(chr);
1520 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1521 }
1522 }
1523 }
1524 catch (AccessViolationException)
1525 {
1526 m_log.Warn("[PHYSICS]: Unable to space collide");
1527 }
1528 }
1529 }
1530
1531 if (removeprims != null)
1532 {
1533 foreach (OdePrim chr in removeprims)
1534 {
1535 _activeprims.Remove(chr);
1536 }
1537 }
1538 }
1539
1540 _perloopContact.Clear();
1541 }
1542
1543 #endregion
1544
1545 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1546 {
1547 m_worldOffset = offset;
1548 WorldExtents = new Vector2(extents.X, extents.Y);
1549 m_parentScene = pScene;
1550 }
1551
1552 // Recovered for use by fly height. Kitto Flora
1553 public float GetTerrainHeightAtXY(float x, float y)
1554 {
1555 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1556 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1557
1558 IntPtr heightFieldGeom = IntPtr.Zero;
1559
1560 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1561 {
1562 if (heightFieldGeom != IntPtr.Zero)
1563 {
1564 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1565 {
1566
1567 int index;
1568
1569
1570 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1571 (int)x < 0.001f || (int)y < 0.001f)
1572 return 0;
1573
1574 x = x - offsetX;
1575 y = y - offsetY;
1576
1577 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1578
1579 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1580 {
1581 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1582 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1583 }
1584
1585 else
1586 return 0f;
1587 }
1588 else
1589 {
1590 return 0f;
1591 }
1592
1593 }
1594 else
1595 {
1596 return 0f;
1597 }
1598
1599 }
1600 else
1601 {
1602 return 0f;
1603 }
1604 }
1605// End recovered. Kitto Flora
1606
1607 public void addCollisionEventReporting(PhysicsActor obj)
1608 {
1609 lock (_collisionEventPrim)
1610 {
1611 if (!_collisionEventPrim.Contains(obj))
1612 _collisionEventPrim.Add(obj);
1613 }
1614 }
1615
1616 public void remCollisionEventReporting(PhysicsActor obj)
1617 {
1618 lock (_collisionEventPrim)
1619 {
1620 if (!_collisionEventPrim.Contains(obj))
1621 _collisionEventPrim.Remove(obj);
1622 }
1623 }
1624
1625 #region Add/Remove Entities
1626
1627 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1628 {
1629 Vector3 pos;
1630 pos.X = position.X;
1631 pos.Y = position.Y;
1632 pos.Z = position.Z;
1633 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1634 newAv.Flying = isFlying;
1635 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1636
1637 return newAv;
1638 }
1639
1640 public void AddCharacter(OdeCharacter chr)
1641 {
1642 lock (_characters)
1643 {
1644 if (!_characters.Contains(chr))
1645 {
1646 _characters.Add(chr);
1647 if (chr.bad)
1648 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1649 }
1650 }
1651 }
1652
1653 public void RemoveCharacter(OdeCharacter chr)
1654 {
1655 lock (_characters)
1656 {
1657 if (_characters.Contains(chr))
1658 {
1659 _characters.Remove(chr);
1660 }
1661 }
1662 }
1663
1664 public void BadCharacter(OdeCharacter chr)
1665 {
1666 lock (_badCharacter)
1667 {
1668 if (!_badCharacter.Contains(chr))
1669 _badCharacter.Add(chr);
1670 }
1671 }
1672
1673 public override void RemoveAvatar(PhysicsActor actor)
1674 {
1675 //m_log.Debug("[PHYSICS]:ODELOCK");
1676 ((OdeCharacter) actor).Destroy();
1677 }
1678
1679 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1680 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1681 {
1682 Vector3 pos = position;
1683 Vector3 siz = size;
1684 Quaternion rot = rotation;
1685
1686 OdePrim newPrim;
1687 lock (OdeLock)
1688 {
1689 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1690
1691 lock (_prims)
1692 _prims.Add(newPrim);
1693 }
1694
1695 return newPrim;
1696 }
1697
1698 public void addActivePrim(OdePrim activatePrim)
1699 {
1700 // adds active prim.. (ones that should be iterated over in collisions_optimized
1701 lock (_activeprims)
1702 {
1703 if (!_activeprims.Contains(activatePrim))
1704 _activeprims.Add(activatePrim);
1705 //else
1706 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1707 }
1708 }
1709
1710 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1711 Vector3 size, Quaternion rotation) //To be removed
1712 {
1713 return AddPrimShape(primName, pbs, position, size, rotation, false);
1714 }
1715
1716 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1717 Vector3 size, Quaternion rotation, bool isPhysical)
1718 {
1719// m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
1720
1721 PhysicsActor result;
1722 IMesh mesh = null;
1723
1724 if (needsMeshing(pbs))
1725 {
1726 try
1727 {
1728 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1729 }
1730 catch(Exception e)
1731 {
1732 m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName);
1733 m_log.Debug(e.ToString());
1734 mesh = null;
1735 return null;
1736 }
1737 }
1738
1739 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1740
1741 return result;
1742 }
1743
1744 public override float TimeDilation
1745 {
1746 get { return m_timeDilation; }
1747 }
1748
1749 public override bool SupportsNINJAJoints
1750 {
1751 get { return m_NINJA_physics_joints_enabled; }
1752 }
1753
1754 // internal utility function: must be called within a lock (OdeLock)
1755 private void InternalAddActiveJoint(PhysicsJoint joint)
1756 {
1757 activeJoints.Add(joint);
1758 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1759 }
1760
1761 // internal utility function: must be called within a lock (OdeLock)
1762 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1763 {
1764 pendingJoints.Add(joint);
1765 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1766 }
1767
1768 // internal utility function: must be called within a lock (OdeLock)
1769 private void InternalRemovePendingJoint(PhysicsJoint joint)
1770 {
1771 pendingJoints.Remove(joint);
1772 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1773 }
1774
1775 // internal utility function: must be called within a lock (OdeLock)
1776 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1777 {
1778 activeJoints.Remove(joint);
1779 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1780 }
1781
1782 public override void DumpJointInfo()
1783 {
1784 string hdr = "[NINJA] JOINTINFO: ";
1785 foreach (PhysicsJoint j in pendingJoints)
1786 {
1787 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1788 }
1789 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1790 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1791 {
1792 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1793 }
1794 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1795 foreach (PhysicsJoint j in activeJoints)
1796 {
1797 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1798 }
1799 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1800 foreach (string jointName in SOPName_to_activeJoint.Keys)
1801 {
1802 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1803 }
1804 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1805
1806 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1807 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1808 foreach (string actorName in joints_connecting_actor.Keys)
1809 {
1810 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1811 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1812 {
1813 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1814 }
1815 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1816 }
1817 }
1818
1819 public override void RequestJointDeletion(string ObjectNameInScene)
1820 {
1821 lock (externalJointRequestsLock)
1822 {
1823 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1824 {
1825 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1826 }
1827 }
1828 }
1829
1830 private void DeleteRequestedJoints()
1831 {
1832 List<string> myRequestedJointsToBeDeleted;
1833 lock (externalJointRequestsLock)
1834 {
1835 // make a local copy of the shared list for processing (threading issues)
1836 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1837 }
1838
1839 foreach (string jointName in myRequestedJointsToBeDeleted)
1840 {
1841 lock (OdeLock)
1842 {
1843 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1844 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1845 {
1846 OdePhysicsJoint joint = null;
1847 if (SOPName_to_activeJoint.ContainsKey(jointName))
1848 {
1849 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1850 InternalRemoveActiveJoint(joint);
1851 }
1852 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1853 {
1854 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1855 InternalRemovePendingJoint(joint);
1856 }
1857
1858 if (joint != null)
1859 {
1860 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1861 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1862 {
1863 string bodyName = joint.BodyNames[iBodyName];
1864 if (bodyName != "NULL")
1865 {
1866 joints_connecting_actor[bodyName].Remove(joint);
1867 if (joints_connecting_actor[bodyName].Count == 0)
1868 {
1869 joints_connecting_actor.Remove(bodyName);
1870 }
1871 }
1872 }
1873
1874 DoJointDeactivated(joint);
1875 if (joint.jointID != IntPtr.Zero)
1876 {
1877 d.JointDestroy(joint.jointID);
1878 joint.jointID = IntPtr.Zero;
1879 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1880 }
1881 else
1882 {
1883 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1884 }
1885 }
1886 else
1887 {
1888 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1889 }
1890 }
1891 else
1892 {
1893 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1894 }
1895 }
1896 }
1897
1898 // remove processed joints from the shared list
1899 lock (externalJointRequestsLock)
1900 {
1901 foreach (string jointName in myRequestedJointsToBeDeleted)
1902 {
1903 requestedJointsToBeDeleted.Remove(jointName);
1904 }
1905 }
1906 }
1907
1908 // for pending joints we don't know if their associated bodies exist yet or not.
1909 // the joint is actually created during processing of the taints
1910 private void CreateRequestedJoints()
1911 {
1912 List<PhysicsJoint> myRequestedJointsToBeCreated;
1913 lock (externalJointRequestsLock)
1914 {
1915 // make a local copy of the shared list for processing (threading issues)
1916 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1917 }
1918
1919 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1920 {
1921 lock (OdeLock)
1922 {
1923 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1924 {
1925 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1926 continue;
1927 }
1928 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1929 {
1930 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1931 continue;
1932 }
1933
1934 InternalAddPendingJoint(joint as OdePhysicsJoint);
1935
1936 if (joint.BodyNames.Count >= 2)
1937 {
1938 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1939 {
1940 string bodyName = joint.BodyNames[iBodyName];
1941 if (bodyName != "NULL")
1942 {
1943 if (!joints_connecting_actor.ContainsKey(bodyName))
1944 {
1945 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1946 }
1947 joints_connecting_actor[bodyName].Add(joint);
1948 }
1949 }
1950 }
1951 }
1952 }
1953
1954 // remove processed joints from shared list
1955 lock (externalJointRequestsLock)
1956 {
1957 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1958 {
1959 requestedJointsToBeCreated.Remove(joint);
1960 }
1961 }
1962 }
1963
1964 /// <summary>
1965 /// Add a request for joint creation.
1966 /// </summary>
1967 /// <remarks>
1968 /// this joint will just be added to a waiting list that is NOT processed during the main
1969 /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
1970 /// </remarks>
1971 /// <param name="objectNameInScene"></param>
1972 /// <param name="jointType"></param>
1973 /// <param name="position"></param>
1974 /// <param name="rotation"></param>
1975 /// <param name="parms"></param>
1976 /// <param name="bodyNames"></param>
1977 /// <param name="trackedBodyName"></param>
1978 /// <param name="localRotation"></param>
1979 /// <returns></returns>
1980 public override PhysicsJoint RequestJointCreation(
1981 string objectNameInScene, PhysicsJointType jointType, Vector3 position,
1982 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
1983 {
1984 OdePhysicsJoint joint = new OdePhysicsJoint();
1985 joint.ObjectNameInScene = objectNameInScene;
1986 joint.Type = jointType;
1987 joint.Position = position;
1988 joint.Rotation = rotation;
1989 joint.RawParams = parms;
1990 joint.BodyNames = new List<string>(bodyNames);
1991 joint.TrackedBodyName = trackedBodyName;
1992 joint.LocalRotation = localRotation;
1993 joint.jointID = IntPtr.Zero;
1994 joint.ErrorMessageCount = 0;
1995
1996 lock (externalJointRequestsLock)
1997 {
1998 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
1999 {
2000 requestedJointsToBeCreated.Add(joint);
2001 }
2002 }
2003
2004 return joint;
2005 }
2006
2007 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2008 {
2009 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2010 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2011 {
2012
2013 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2014 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2015 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2016 {
2017 jointsToRemove.Add(j);
2018 }
2019 foreach (PhysicsJoint j in jointsToRemove)
2020 {
2021 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2022 RequestJointDeletion(j.ObjectNameInScene);
2023 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2024 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2025 }
2026 }
2027 }
2028
2029 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2030 {
2031 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2032 lock (OdeLock)
2033 {
2034 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2035 RemoveAllJointsConnectedToActor(actor);
2036 }
2037 }
2038
2039 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2040 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2041 {
2042 Debug.Assert(joint.IsInPhysicsEngine);
2043 d.Vector3 pos = new d.Vector3();
2044
2045 if (!(joint is OdePhysicsJoint))
2046 {
2047 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2048 }
2049 else
2050 {
2051 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2052 switch (odeJoint.Type)
2053 {
2054 case PhysicsJointType.Ball:
2055 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2056 break;
2057 case PhysicsJointType.Hinge:
2058 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2059 break;
2060 }
2061 }
2062 return new Vector3(pos.X, pos.Y, pos.Z);
2063 }
2064
2065 /// <summary>
2066 /// Get joint axis.
2067 /// </summary>
2068 /// <remarks>
2069 /// normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2070 /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2071 /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2072 /// keeping track of the joint's original orientation relative to one of the involved bodies.
2073 /// </remarks>
2074 /// <param name="joint"></param>
2075 /// <returns></returns>
2076 public override Vector3 GetJointAxis(PhysicsJoint joint)
2077 {
2078 Debug.Assert(joint.IsInPhysicsEngine);
2079 d.Vector3 axis = new d.Vector3();
2080
2081 if (!(joint is OdePhysicsJoint))
2082 {
2083 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2084 }
2085 else
2086 {
2087 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2088 switch (odeJoint.Type)
2089 {
2090 case PhysicsJointType.Ball:
2091 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2092 break;
2093 case PhysicsJointType.Hinge:
2094 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2095 break;
2096 }
2097 }
2098 return new Vector3(axis.X, axis.Y, axis.Z);
2099 }
2100
2101 public void remActivePrim(OdePrim deactivatePrim)
2102 {
2103 lock (_activeprims)
2104 {
2105 _activeprims.Remove(deactivatePrim);
2106 }
2107 }
2108
2109 public override void RemovePrim(PhysicsActor prim)
2110 {
2111 if (prim is OdePrim)
2112 {
2113 lock (OdeLock)
2114 {
2115 OdePrim p = (OdePrim) prim;
2116
2117 p.setPrimForRemoval();
2118 AddPhysicsActorTaint(prim);
2119 //RemovePrimThreadLocked(p);
2120 }
2121 }
2122 }
2123
2124 /// <summary>
2125 /// This is called from within simulate but outside the locked portion
2126 /// We need to do our own locking here
2127 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2128 ///
2129 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2130 /// that the space was using.
2131 /// </summary>
2132 /// <param name="prim"></param>
2133 public void RemovePrimThreadLocked(OdePrim prim)
2134 {
2135//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2136 lock (prim)
2137 {
2138 remCollisionEventReporting(prim);
2139 lock (ode)
2140 {
2141 if (prim.prim_geom != IntPtr.Zero)
2142 {
2143 prim.ResetTaints();
2144
2145 if (prim.IsPhysical)
2146 {
2147 prim.disableBody();
2148 if (prim.childPrim)
2149 {
2150 prim.childPrim = false;
2151 prim.Body = IntPtr.Zero;
2152 prim.m_disabled = true;
2153 prim.IsPhysical = false;
2154 }
2155
2156
2157 }
2158 // we don't want to remove the main space
2159
2160 // If the geometry is in the targetspace, remove it from the target space
2161 //m_log.Warn(prim.m_targetSpace);
2162
2163 //if (prim.m_targetSpace != IntPtr.Zero)
2164 //{
2165 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2166 //{
2167
2168 //if (d.GeomIsSpace(prim.m_targetSpace))
2169 //{
2170 //waitForSpaceUnlock(prim.m_targetSpace);
2171 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2172 prim.m_targetSpace = IntPtr.Zero;
2173 //}
2174 //else
2175 //{
2176 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2177 //((OdePrim)prim).m_targetSpace.ToString());
2178 //}
2179
2180 //}
2181 //}
2182 //m_log.Warn(prim.prim_geom);
2183 try
2184 {
2185 if (prim.prim_geom != IntPtr.Zero)
2186 {
2187 d.GeomDestroy(prim.prim_geom);
2188 prim.prim_geom = IntPtr.Zero;
2189 }
2190 else
2191 {
2192 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2193 }
2194 }
2195 catch (AccessViolationException)
2196 {
2197 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2198 }
2199 lock (_prims)
2200 _prims.Remove(prim);
2201
2202 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2203 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2204 //{
2205 //if (prim.m_targetSpace != null)
2206 //{
2207 //if (d.GeomIsSpace(prim.m_targetSpace))
2208 //{
2209 //waitForSpaceUnlock(prim.m_targetSpace);
2210 //d.SpaceRemove(space, prim.m_targetSpace);
2211 // free up memory used by the space.
2212 //d.SpaceDestroy(prim.m_targetSpace);
2213 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2214 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2215 //}
2216 //else
2217 //{
2218 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2219 //((OdePrim) prim).m_targetSpace.ToString());
2220 //}
2221 //}
2222 //}
2223
2224 if (SupportsNINJAJoints)
2225 {
2226 RemoveAllJointsConnectedToActorThreadLocked(prim);
2227 }
2228 }
2229 }
2230 }
2231 }
2232
2233 #endregion
2234
2235 #region Space Separation Calculation
2236
2237 /// <summary>
2238 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2239 /// </summary>
2240 /// <param name="pSpace"></param>
2241 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2242 {
2243 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2244 {
2245 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2246 {
2247 if (staticPrimspace[x, y] == pSpace)
2248 staticPrimspace[x, y] = IntPtr.Zero;
2249 }
2250 }
2251 }
2252
2253 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2254 {
2255 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2256 }
2257
2258 /// <summary>
2259 /// Called when a static prim moves. Allocates a space for the prim based on its position
2260 /// </summary>
2261 /// <param name="geom">the pointer to the geom that moved</param>
2262 /// <param name="pos">the position that the geom moved to</param>
2263 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2264 /// <returns>a pointer to the new space it's in</returns>
2265 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2266 {
2267 // Called from setting the Position and Size of an ODEPrim so
2268 // it's already in locked space.
2269
2270 // we don't want to remove the main space
2271 // we don't need to test physical here because this function should
2272 // never be called if the prim is physical(active)
2273
2274 // All physical prim end up in the root space
2275 //Thread.Sleep(20);
2276 if (currentspace != space)
2277 {
2278 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2279 //if (currentspace == IntPtr.Zero)
2280 //{
2281 //int adfadf = 0;
2282 //}
2283 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2284 {
2285 if (d.GeomIsSpace(currentspace))
2286 {
2287 waitForSpaceUnlock(currentspace);
2288 d.SpaceRemove(currentspace, geom);
2289 }
2290 else
2291 {
2292 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2293 " Geom:" + geom);
2294 }
2295 }
2296 else
2297 {
2298 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2299 if (sGeomIsIn != IntPtr.Zero)
2300 {
2301 if (d.GeomIsSpace(currentspace))
2302 {
2303 waitForSpaceUnlock(sGeomIsIn);
2304 d.SpaceRemove(sGeomIsIn, geom);
2305 }
2306 else
2307 {
2308 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2309 sGeomIsIn + " Geom:" + geom);
2310 }
2311 }
2312 }
2313
2314 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2315 if (d.SpaceGetNumGeoms(currentspace) == 0)
2316 {
2317 if (currentspace != IntPtr.Zero)
2318 {
2319 if (d.GeomIsSpace(currentspace))
2320 {
2321 waitForSpaceUnlock(currentspace);
2322 waitForSpaceUnlock(space);
2323 d.SpaceRemove(space, currentspace);
2324 // free up memory used by the space.
2325
2326 //d.SpaceDestroy(currentspace);
2327 resetSpaceArrayItemToZero(currentspace);
2328 }
2329 else
2330 {
2331 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2332 currentspace + " Geom:" + geom);
2333 }
2334 }
2335 }
2336 }
2337 else
2338 {
2339 // this is a physical object that got disabled. ;.;
2340 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2341 {
2342 if (d.SpaceQuery(currentspace, geom))
2343 {
2344 if (d.GeomIsSpace(currentspace))
2345 {
2346 waitForSpaceUnlock(currentspace);
2347 d.SpaceRemove(currentspace, geom);
2348 }
2349 else
2350 {
2351 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2352 currentspace + " Geom:" + geom);
2353 }
2354 }
2355 else
2356 {
2357 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2358 if (sGeomIsIn != IntPtr.Zero)
2359 {
2360 if (d.GeomIsSpace(sGeomIsIn))
2361 {
2362 waitForSpaceUnlock(sGeomIsIn);
2363 d.SpaceRemove(sGeomIsIn, geom);
2364 }
2365 else
2366 {
2367 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2368 sGeomIsIn + " Geom:" + geom);
2369 }
2370 }
2371 }
2372 }
2373 }
2374
2375 // The routines in the Position and Size sections do the 'inserting' into the space,
2376 // so all we have to do is make sure that the space that we're putting the prim into
2377 // is in the 'main' space.
2378 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2379 IntPtr newspace = calculateSpaceForGeom(pos);
2380
2381 if (newspace == IntPtr.Zero)
2382 {
2383 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2384 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2385 }
2386
2387 return newspace;
2388 }
2389
2390 /// <summary>
2391 /// Creates a new space at X Y
2392 /// </summary>
2393 /// <param name="iprimspaceArrItemX"></param>
2394 /// <param name="iprimspaceArrItemY"></param>
2395 /// <returns>A pointer to the created space</returns>
2396 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2397 {
2398 // creating a new space for prim and inserting it into main space.
2399 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2400 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2401 waitForSpaceUnlock(space);
2402 d.SpaceSetSublevel(space, 1);
2403 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2404 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2405 }
2406
2407 /// <summary>
2408 /// Calculates the space the prim should be in by its position
2409 /// </summary>
2410 /// <param name="pos"></param>
2411 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2412 public IntPtr calculateSpaceForGeom(Vector3 pos)
2413 {
2414 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2415 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2416 return staticPrimspace[xyspace[0], xyspace[1]];
2417 }
2418
2419 /// <summary>
2420 /// Holds the space allocation logic
2421 /// </summary>
2422 /// <param name="pos"></param>
2423 /// <returns>an array item based on the position</returns>
2424 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2425 {
2426 int[] returnint = new int[2];
2427
2428 returnint[0] = (int) (pos.X/metersInSpace);
2429
2430 if (returnint[0] > ((int) (259f/metersInSpace)))
2431 returnint[0] = ((int) (259f/metersInSpace));
2432 if (returnint[0] < 0)
2433 returnint[0] = 0;
2434
2435 returnint[1] = (int) (pos.Y/metersInSpace);
2436 if (returnint[1] > ((int) (259f/metersInSpace)))
2437 returnint[1] = ((int) (259f/metersInSpace));
2438 if (returnint[1] < 0)
2439 returnint[1] = 0;
2440
2441 return returnint;
2442 }
2443
2444 #endregion
2445
2446 /// <summary>
2447 /// Routine to figure out if we need to mesh this prim with our mesher
2448 /// </summary>
2449 /// <param name="pbs"></param>
2450 /// <returns></returns>
2451 public bool needsMeshing(PrimitiveBaseShape pbs)
2452 {
2453 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2454 // but we still need to check for sculptie meshing being enabled so this is the most
2455 // convenient place to do it for now...
2456
2457 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2458 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2459 int iPropertiesNotSupportedDefault = 0;
2460
2461 if (pbs.SculptEntry && !meshSculptedPrim)
2462 {
2463#if SPAM
2464 m_log.Warn("NonMesh");
2465#endif
2466 return false;
2467 }
2468
2469 // 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
2470 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2471 {
2472 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2473 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2474 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2475 {
2476
2477 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2478 && pbs.ProfileHollow == 0
2479 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2480 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2481 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2482 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2483 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2484 {
2485#if SPAM
2486 m_log.Warn("NonMesh");
2487#endif
2488 return false;
2489 }
2490 }
2491 }
2492
2493 if (pbs.ProfileHollow != 0)
2494 iPropertiesNotSupportedDefault++;
2495
2496 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2497 iPropertiesNotSupportedDefault++;
2498
2499 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2500 iPropertiesNotSupportedDefault++;
2501
2502 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2503 iPropertiesNotSupportedDefault++;
2504
2505 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2506 iPropertiesNotSupportedDefault++;
2507
2508 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2509 iPropertiesNotSupportedDefault++;
2510
2511 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2512 iPropertiesNotSupportedDefault++;
2513
2514 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))
2515 iPropertiesNotSupportedDefault++;
2516
2517 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2518 iPropertiesNotSupportedDefault++;
2519
2520 // test for torus
2521 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2522 {
2523 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2524 {
2525 iPropertiesNotSupportedDefault++;
2526 }
2527 }
2528 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2529 {
2530 if (pbs.PathCurve == (byte)Extrusion.Straight)
2531 {
2532 iPropertiesNotSupportedDefault++;
2533 }
2534
2535 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2536 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2537 {
2538 iPropertiesNotSupportedDefault++;
2539 }
2540 }
2541 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2542 {
2543 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2544 {
2545 iPropertiesNotSupportedDefault++;
2546 }
2547 }
2548 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2549 {
2550 if (pbs.PathCurve == (byte)Extrusion.Straight)
2551 {
2552 iPropertiesNotSupportedDefault++;
2553 }
2554 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2555 {
2556 iPropertiesNotSupportedDefault++;
2557 }
2558 }
2559
2560 if (pbs.SculptEntry && meshSculptedPrim)
2561 iPropertiesNotSupportedDefault++;
2562
2563
2564 if (iPropertiesNotSupportedDefault == 0)
2565 {
2566#if SPAM
2567 m_log.Warn("NonMesh");
2568#endif
2569 return false;
2570 }
2571#if SPAM
2572 m_log.Debug("Mesh");
2573#endif
2574 return true;
2575 }
2576
2577 /// <summary>
2578 /// Called after our prim properties are set Scale, position etc.
2579 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2580 /// This assures us that we have no race conditions
2581 /// </summary>
2582 /// <param name="prim"></param>
2583 public override void AddPhysicsActorTaint(PhysicsActor prim)
2584 {
2585 if (prim is OdePrim)
2586 {
2587 OdePrim taintedprim = ((OdePrim) prim);
2588 lock (_taintedPrimLock)
2589 {
2590 if (!(_taintedPrimH.Contains(taintedprim)))
2591 {
2592//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2593 _taintedPrimH.Add(taintedprim); // HashSet for searching
2594 _taintedPrimL.Add(taintedprim); // List for ordered readout
2595 }
2596 }
2597 return;
2598 }
2599 else if (prim is OdeCharacter)
2600 {
2601 OdeCharacter taintedchar = ((OdeCharacter)prim);
2602 lock (_taintedActors)
2603 {
2604 if (!(_taintedActors.Contains(taintedchar)))
2605 {
2606 _taintedActors.Add(taintedchar);
2607 if (taintedchar.bad)
2608 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2609 }
2610 }
2611 }
2612 }
2613
2614 /// <summary>
2615 /// This is our main simulate loop
2616 /// It's thread locked by a Mutex in the scene.
2617 /// It holds Collisions, it instructs ODE to step through the physical reactions
2618 /// It moves the objects around in memory
2619 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2620 /// </summary>
2621 /// <param name="timeStep"></param>
2622 /// <returns></returns>
2623 public override float Simulate(float timeStep)
2624 {
2625 if (framecount >= int.MaxValue)
2626 framecount = 0;
2627
2628 //if (m_worldOffset != Vector3.Zero)
2629 // return 0;
2630
2631 framecount++;
2632
2633 float fps = 0;
2634 //m_log.Info(timeStep.ToString());
2635 step_time += timeStep;
2636
2637 // If We're loaded down by something else,
2638 // or debugging with the Visual Studio project on pause
2639 // skip a few frames to catch up gracefully.
2640 // without shooting the physicsactors all over the place
2641
2642 if (step_time >= m_SkipFramesAtms)
2643 {
2644 // Instead of trying to catch up, it'll do 5 physics frames only
2645 step_time = ODE_STEPSIZE;
2646 m_physicsiterations = 5;
2647 }
2648 else
2649 {
2650 m_physicsiterations = 10;
2651 }
2652
2653 if (SupportsNINJAJoints)
2654 {
2655 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2656 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2657 }
2658
2659 lock (OdeLock)
2660 {
2661 // Process 10 frames if the sim is running normal..
2662 // process 5 frames if the sim is running slow
2663 //try
2664 //{
2665 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2666 //}
2667 //catch (StackOverflowException)
2668 //{
2669 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2670 // ode.drelease(world);
2671 //base.TriggerPhysicsBasedRestart();
2672 //}
2673
2674 int i = 0;
2675
2676 // Figure out the Frames Per Second we're going at.
2677 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2678
2679 fps = (step_time / ODE_STEPSIZE) * 1000;
2680 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2681 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2682
2683 step_time = 0.09375f;
2684
2685 while (step_time > 0.0f)
2686 {
2687 //lock (ode)
2688 //{
2689 //if (!ode.lockquery())
2690 //{
2691 // ode.dlock(world);
2692 try
2693 {
2694 // Insert, remove Characters
2695 bool processedtaints = false;
2696
2697 lock (_taintedActors)
2698 {
2699 if (_taintedActors.Count > 0)
2700 {
2701 foreach (OdeCharacter character in _taintedActors)
2702 {
2703
2704 character.ProcessTaints(timeStep);
2705
2706 processedtaints = true;
2707 //character.m_collisionscore = 0;
2708 }
2709
2710 if (processedtaints)
2711 _taintedActors.Clear();
2712 }
2713 }
2714
2715 // Modify other objects in the scene.
2716 processedtaints = false;
2717
2718 lock (_taintedPrimLock)
2719 {
2720 foreach (OdePrim prim in _taintedPrimL)
2721 {
2722 if (prim.m_taintremove)
2723 {
2724 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2725 RemovePrimThreadLocked(prim);
2726 }
2727 else
2728 {
2729 //Console.WriteLine("Simulate calls ProcessTaints");
2730 prim.ProcessTaints(timeStep);
2731 }
2732 processedtaints = true;
2733 prim.m_collisionscore = 0;
2734
2735 // This loop can block up the Heartbeat for a very long time on large regions.
2736 // We need to let the Watchdog know that the Heartbeat is not dead
2737 // NOTE: This is currently commented out, but if things like OAR loading are
2738 // timing the heartbeat out we will need to uncomment it
2739 //Watchdog.UpdateThread();
2740 }
2741
2742 if (SupportsNINJAJoints)
2743 {
2744 // Create pending joints, if possible
2745
2746 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2747 // a joint requires specifying the body id of both involved bodies
2748 if (pendingJoints.Count > 0)
2749 {
2750 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2751 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2752 foreach (PhysicsJoint joint in pendingJoints)
2753 {
2754 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2755 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2756 List<IntPtr> jointBodies = new List<IntPtr>();
2757 bool allJointBodiesAreReady = true;
2758 foreach (string jointParam in jointParams)
2759 {
2760 if (jointParam == "NULL")
2761 {
2762 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2763 jointBodies.Add(IntPtr.Zero);
2764 }
2765 else
2766 {
2767 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2768 bool foundPrim = false;
2769 lock (_prims)
2770 {
2771 foreach (OdePrim prim in _prims) // FIXME: inefficient
2772 {
2773 if (prim.SOPName == jointParam)
2774 {
2775 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2776 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2777 {
2778 jointBodies.Add(prim.Body);
2779 foundPrim = true;
2780 break;
2781 }
2782 else
2783 {
2784 DoJointErrorMessage(joint, "prim name " + jointParam +
2785 " exists but is not (yet) physical; deferring joint creation. " +
2786 "IsPhysical property is " + prim.IsPhysical +
2787 " and body is " + prim.Body);
2788 foundPrim = false;
2789 break;
2790 }
2791 }
2792 }
2793 }
2794 if (foundPrim)
2795 {
2796 // all is fine
2797 }
2798 else
2799 {
2800 allJointBodiesAreReady = false;
2801 break;
2802 }
2803 }
2804 }
2805 if (allJointBodiesAreReady)
2806 {
2807 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2808 if (jointBodies[0] == jointBodies[1])
2809 {
2810 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2811 }
2812 else
2813 {
2814 switch (joint.Type)
2815 {
2816 case PhysicsJointType.Ball:
2817 {
2818 IntPtr odeJoint;
2819 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2820 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2821 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2822 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2823 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2824 d.JointSetBallAnchor(odeJoint,
2825 joint.Position.X,
2826 joint.Position.Y,
2827 joint.Position.Z);
2828 //DoJointErrorMessage(joint, "ODE joint setting OK");
2829 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2830 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2831 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2832 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2833
2834 if (joint is OdePhysicsJoint)
2835 {
2836 ((OdePhysicsJoint)joint).jointID = odeJoint;
2837 }
2838 else
2839 {
2840 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2841 }
2842 }
2843 break;
2844 case PhysicsJointType.Hinge:
2845 {
2846 IntPtr odeJoint;
2847 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2848 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2849 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2850 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2851 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2852 d.JointSetHingeAnchor(odeJoint,
2853 joint.Position.X,
2854 joint.Position.Y,
2855 joint.Position.Z);
2856 // We use the orientation of the x-axis of the joint's coordinate frame
2857 // as the axis for the hinge.
2858
2859 // Therefore, we must get the joint's coordinate frame based on the
2860 // joint.Rotation field, which originates from the orientation of the
2861 // joint's proxy object in the scene.
2862
2863 // The joint's coordinate frame is defined as the transformation matrix
2864 // that converts a vector from joint-local coordinates into world coordinates.
2865 // World coordinates are defined as the XYZ coordinate system of the sim,
2866 // as shown in the top status-bar of the viewer.
2867
2868 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2869 // and use that as the hinge axis.
2870
2871 //joint.Rotation.Normalize();
2872 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2873
2874 // Now extract the X axis of the joint's coordinate frame.
2875
2876 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2877 // tar pit of transposed, inverted, and generally messed-up orientations.
2878 // (In other words, Matrix4.AtAxis() is borked.)
2879 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2880
2881 // Instead, compute the X axis of the coordinate frame by transforming
2882 // the (1,0,0) vector. At least that works.
2883
2884 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2885 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2886 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2887 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2888 d.JointSetHingeAxis(odeJoint,
2889 jointAxis.X,
2890 jointAxis.Y,
2891 jointAxis.Z);
2892 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2893 if (joint is OdePhysicsJoint)
2894 {
2895 ((OdePhysicsJoint)joint).jointID = odeJoint;
2896 }
2897 else
2898 {
2899 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2900 }
2901 }
2902 break;
2903 }
2904 successfullyProcessedPendingJoints.Add(joint);
2905 }
2906 }
2907 else
2908 {
2909 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2910 }
2911 }
2912 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2913 {
2914 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2915 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2916 InternalRemovePendingJoint(successfullyProcessedJoint);
2917 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2918 InternalAddActiveJoint(successfullyProcessedJoint);
2919 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2920 }
2921 }
2922 }
2923
2924 if (processedtaints)
2925//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2926 _taintedPrimH.Clear();
2927 _taintedPrimL.Clear();
2928 }
2929
2930 // Move characters
2931 lock (_characters)
2932 {
2933 List<OdeCharacter> defects = new List<OdeCharacter>();
2934 foreach (OdeCharacter actor in _characters)
2935 {
2936 if (actor != null)
2937 actor.Move(timeStep, defects);
2938 }
2939 if (0 != defects.Count)
2940 {
2941 foreach (OdeCharacter defect in defects)
2942 {
2943 RemoveCharacter(defect);
2944 }
2945 }
2946 }
2947
2948 // Move other active objects
2949 lock (_activeprims)
2950 {
2951 foreach (OdePrim prim in _activeprims)
2952 {
2953 prim.m_collisionscore = 0;
2954 prim.Move(timeStep);
2955 }
2956 }
2957
2958 //if ((framecount % m_randomizeWater) == 0)
2959 // randomizeWater(waterlevel);
2960
2961 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2962 m_rayCastManager.ProcessQueuedRequests();
2963
2964 collision_optimized(timeStep);
2965
2966 lock (_collisionEventPrim)
2967 {
2968 foreach (PhysicsActor obj in _collisionEventPrim)
2969 {
2970 if (obj == null)
2971 continue;
2972
2973 switch ((ActorTypes)obj.PhysicsActorType)
2974 {
2975 case ActorTypes.Agent:
2976 OdeCharacter cobj = (OdeCharacter)obj;
2977 cobj.AddCollisionFrameTime(100);
2978 cobj.SendCollisions();
2979 break;
2980 case ActorTypes.Prim:
2981 OdePrim pobj = (OdePrim)obj;
2982 pobj.SendCollisions();
2983 break;
2984 }
2985 }
2986 }
2987
2988 //if (m_global_contactcount > 5)
2989 //{
2990 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
2991 //}
2992
2993 m_global_contactcount = 0;
2994
2995 d.WorldQuickStep(world, ODE_STEPSIZE);
2996 d.JointGroupEmpty(contactgroup);
2997 //ode.dunlock(world);
2998 }
2999 catch (Exception e)
3000 {
3001 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3002 ode.dunlock(world);
3003 }
3004
3005 step_time -= ODE_STEPSIZE;
3006 i++;
3007 //}
3008 //else
3009 //{
3010 //fps = 0;
3011 //}
3012 //}
3013 }
3014
3015 lock (_characters)
3016 {
3017 foreach (OdeCharacter actor in _characters)
3018 {
3019 if (actor != null)
3020 {
3021 if (actor.bad)
3022 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3023 actor.UpdatePositionAndVelocity();
3024 }
3025 }
3026 }
3027
3028 lock (_badCharacter)
3029 {
3030 if (_badCharacter.Count > 0)
3031 {
3032 foreach (OdeCharacter chr in _badCharacter)
3033 {
3034 RemoveCharacter(chr);
3035 }
3036 _badCharacter.Clear();
3037 }
3038 }
3039
3040 lock (_activeprims)
3041 {
3042 //if (timeStep < 0.2f)
3043 {
3044 foreach (OdePrim actor in _activeprims)
3045 {
3046 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3047 {
3048 actor.UpdatePositionAndVelocity();
3049
3050 if (SupportsNINJAJoints)
3051 {
3052 // If an actor moved, move its joint proxy objects as well.
3053 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3054 // for this purpose but it is never called! So we just do the joint
3055 // movement code here.
3056
3057 if (actor.SOPName != null &&
3058 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3059 joints_connecting_actor[actor.SOPName] != null &&
3060 joints_connecting_actor[actor.SOPName].Count > 0)
3061 {
3062 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3063 {
3064 if (affectedJoint.IsInPhysicsEngine)
3065 {
3066 DoJointMoved(affectedJoint);
3067 }
3068 else
3069 {
3070 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3071 }
3072 }
3073 }
3074 }
3075 }
3076 }
3077 }
3078 }
3079
3080 //DumpJointInfo();
3081
3082 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3083 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3084 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3085 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3086 {
3087 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3088 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3089
3090 if (physics_logging_append_existing_logfile)
3091 {
3092 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3093 TextWriter fwriter = File.AppendText(fname);
3094 fwriter.WriteLine(header);
3095 fwriter.Close();
3096 }
3097 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3098 }
3099 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
3100
3101 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3102 // has a max of 100 ms to run theoretically.
3103 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3104 // If Physics stalls, it takes longer which makes the tick count ms larger.
3105
3106 if (latertickcount < 100)
3107 m_timeDilation = 1.0f;
3108 else
3109 {
3110 m_timeDilation = 100f / latertickcount;
3111 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3112 }
3113
3114 tickCountFrameRun = Util.EnvironmentTickCount();
3115 }
3116
3117 return fps;
3118 }
3119
3120 public override void GetResults()
3121 {
3122 }
3123
3124 public override bool IsThreaded
3125 {
3126 // for now we won't be multithreaded
3127 get { return (false); }
3128 }
3129
3130 #region ODE Specific Terrain Fixes
3131 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3132 {
3133 float[] returnarr = new float[262144];
3134 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3135
3136 // Filling out the array into its multi-dimensional components
3137 for (int y = 0; y < WorldExtents.Y; y++)
3138 {
3139 for (int x = 0; x < WorldExtents.X; x++)
3140 {
3141 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3142 }
3143 }
3144
3145 // Resize using Nearest Neighbour
3146
3147 // This particular way is quick but it only works on a multiple of the original
3148
3149 // The idea behind this method can be described with the following diagrams
3150 // second pass and third pass happen in the same loop really.. just separated
3151 // them to show what this does.
3152
3153 // First Pass
3154 // ResultArr:
3155 // 1,1,1,1,1,1
3156 // 1,1,1,1,1,1
3157 // 1,1,1,1,1,1
3158 // 1,1,1,1,1,1
3159 // 1,1,1,1,1,1
3160 // 1,1,1,1,1,1
3161
3162 // Second Pass
3163 // ResultArr2:
3164 // 1,,1,,1,,1,,1,,1,
3165 // ,,,,,,,,,,
3166 // 1,,1,,1,,1,,1,,1,
3167 // ,,,,,,,,,,
3168 // 1,,1,,1,,1,,1,,1,
3169 // ,,,,,,,,,,
3170 // 1,,1,,1,,1,,1,,1,
3171 // ,,,,,,,,,,
3172 // 1,,1,,1,,1,,1,,1,
3173 // ,,,,,,,,,,
3174 // 1,,1,,1,,1,,1,,1,
3175
3176 // Third pass fills in the blanks
3177 // ResultArr2:
3178 // 1,1,1,1,1,1,1,1,1,1,1,1
3179 // 1,1,1,1,1,1,1,1,1,1,1,1
3180 // 1,1,1,1,1,1,1,1,1,1,1,1
3181 // 1,1,1,1,1,1,1,1,1,1,1,1
3182 // 1,1,1,1,1,1,1,1,1,1,1,1
3183 // 1,1,1,1,1,1,1,1,1,1,1,1
3184 // 1,1,1,1,1,1,1,1,1,1,1,1
3185 // 1,1,1,1,1,1,1,1,1,1,1,1
3186 // 1,1,1,1,1,1,1,1,1,1,1,1
3187 // 1,1,1,1,1,1,1,1,1,1,1,1
3188 // 1,1,1,1,1,1,1,1,1,1,1,1
3189
3190 // X,Y = .
3191 // X+1,y = ^
3192 // X,Y+1 = *
3193 // X+1,Y+1 = #
3194
3195 // Filling in like this;
3196 // .*
3197 // ^#
3198 // 1st .
3199 // 2nd *
3200 // 3rd ^
3201 // 4th #
3202 // on single loop.
3203
3204 float[,] resultarr2 = new float[512, 512];
3205 for (int y = 0; y < WorldExtents.Y; y++)
3206 {
3207 for (int x = 0; x < WorldExtents.X; x++)
3208 {
3209 resultarr2[y * 2, x * 2] = resultarr[y, x];
3210
3211 if (y < WorldExtents.Y)
3212 {
3213 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3214 }
3215 if (x < WorldExtents.X)
3216 {
3217 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3218 }
3219 if (x < WorldExtents.X && y < WorldExtents.Y)
3220 {
3221 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3222 }
3223 }
3224 }
3225
3226 //Flatten out the array
3227 int i = 0;
3228 for (int y = 0; y < 512; y++)
3229 {
3230 for (int x = 0; x < 512; x++)
3231 {
3232 if (resultarr2[y, x] <= 0)
3233 returnarr[i] = 0.0000001f;
3234 else
3235 returnarr[i] = resultarr2[y, x];
3236
3237 i++;
3238 }
3239 }
3240
3241 return returnarr;
3242 }
3243
3244 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3245 {
3246 float[] returnarr = new float[262144];
3247 float[,] resultarr = new float[512,512];
3248
3249 // Filling out the array into its multi-dimensional components
3250 for (int y = 0; y < 256; y++)
3251 {
3252 for (int x = 0; x < 256; x++)
3253 {
3254 resultarr[y, x] = heightMap[y * 256 + x];
3255 }
3256 }
3257
3258 // Resize using interpolation
3259
3260 // This particular way is quick but it only works on a multiple of the original
3261
3262 // The idea behind this method can be described with the following diagrams
3263 // second pass and third pass happen in the same loop really.. just separated
3264 // them to show what this does.
3265
3266 // First Pass
3267 // ResultArr:
3268 // 1,1,1,1,1,1
3269 // 1,1,1,1,1,1
3270 // 1,1,1,1,1,1
3271 // 1,1,1,1,1,1
3272 // 1,1,1,1,1,1
3273 // 1,1,1,1,1,1
3274
3275 // Second Pass
3276 // ResultArr2:
3277 // 1,,1,,1,,1,,1,,1,
3278 // ,,,,,,,,,,
3279 // 1,,1,,1,,1,,1,,1,
3280 // ,,,,,,,,,,
3281 // 1,,1,,1,,1,,1,,1,
3282 // ,,,,,,,,,,
3283 // 1,,1,,1,,1,,1,,1,
3284 // ,,,,,,,,,,
3285 // 1,,1,,1,,1,,1,,1,
3286 // ,,,,,,,,,,
3287 // 1,,1,,1,,1,,1,,1,
3288
3289 // Third pass fills in the blanks
3290 // ResultArr2:
3291 // 1,1,1,1,1,1,1,1,1,1,1,1
3292 // 1,1,1,1,1,1,1,1,1,1,1,1
3293 // 1,1,1,1,1,1,1,1,1,1,1,1
3294 // 1,1,1,1,1,1,1,1,1,1,1,1
3295 // 1,1,1,1,1,1,1,1,1,1,1,1
3296 // 1,1,1,1,1,1,1,1,1,1,1,1
3297 // 1,1,1,1,1,1,1,1,1,1,1,1
3298 // 1,1,1,1,1,1,1,1,1,1,1,1
3299 // 1,1,1,1,1,1,1,1,1,1,1,1
3300 // 1,1,1,1,1,1,1,1,1,1,1,1
3301 // 1,1,1,1,1,1,1,1,1,1,1,1
3302
3303 // X,Y = .
3304 // X+1,y = ^
3305 // X,Y+1 = *
3306 // X+1,Y+1 = #
3307
3308 // Filling in like this;
3309 // .*
3310 // ^#
3311 // 1st .
3312 // 2nd *
3313 // 3rd ^
3314 // 4th #
3315 // on single loop.
3316
3317 float[,] resultarr2 = new float[512,512];
3318 for (int y = 0; y < (int)Constants.RegionSize; y++)
3319 {
3320 for (int x = 0; x < (int)Constants.RegionSize; x++)
3321 {
3322 resultarr2[y*2, x*2] = resultarr[y, x];
3323
3324 if (y < (int)Constants.RegionSize)
3325 {
3326 if (y + 1 < (int)Constants.RegionSize)
3327 {
3328 if (x + 1 < (int)Constants.RegionSize)
3329 {
3330 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3331 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3332 }
3333 else
3334 {
3335 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3336 }
3337 }
3338 else
3339 {
3340 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3341 }
3342 }
3343 if (x < (int)Constants.RegionSize)
3344 {
3345 if (x + 1 < (int)Constants.RegionSize)
3346 {
3347 if (y + 1 < (int)Constants.RegionSize)
3348 {
3349 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3350 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3351 }
3352 else
3353 {
3354 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3355 }
3356 }
3357 else
3358 {
3359 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3360 }
3361 }
3362 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3363 {
3364 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3365 {
3366 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3367 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3368 }
3369 else
3370 {
3371 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3372 }
3373 }
3374 }
3375 }
3376 //Flatten out the array
3377 int i = 0;
3378 for (int y = 0; y < 512; y++)
3379 {
3380 for (int x = 0; x < 512; x++)
3381 {
3382 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3383 {
3384 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3385 resultarr2[y, x] = 0;
3386 }
3387 returnarr[i] = resultarr2[y, x];
3388 i++;
3389 }
3390 }
3391
3392 return returnarr;
3393 }
3394
3395 #endregion
3396
3397 public override void SetTerrain(float[] heightMap)
3398 {
3399 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3400 {
3401 if (m_parentScene is OdeScene)
3402 {
3403 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3404 }
3405 }
3406 else
3407 {
3408 SetTerrain(heightMap, m_worldOffset);
3409 }
3410 }
3411
3412 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3413 {
3414 // this._heightmap[i] = (double)heightMap[i];
3415 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3416 //_origheightmap = heightMap;
3417
3418 float[] _heightmap;
3419
3420 // zero out a heightmap array float array (single dimension [flattened]))
3421 //if ((int)Constants.RegionSize == 256)
3422 // _heightmap = new float[514 * 514];
3423 //else
3424
3425 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3426
3427 uint heightmapWidth = Constants.RegionSize + 1;
3428 uint heightmapHeight = Constants.RegionSize + 1;
3429
3430 uint heightmapWidthSamples;
3431
3432 uint heightmapHeightSamples;
3433
3434 //if (((int)Constants.RegionSize) == 256)
3435 //{
3436 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3437 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3438 // heightmapWidth++;
3439 // heightmapHeight++;
3440 //}
3441 //else
3442 //{
3443
3444 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3445 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3446 //}
3447
3448 const float scale = 1.0f;
3449 const float offset = 0.0f;
3450 const float thickness = 0.2f;
3451 const int wrap = 0;
3452
3453 int regionsize = (int) Constants.RegionSize + 2;
3454 //Double resolution
3455 //if (((int)Constants.RegionSize) == 256)
3456 // heightMap = ResizeTerrain512Interpolation(heightMap);
3457
3458
3459 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3460 // regionsize = 512;
3461
3462 float hfmin = 2000;
3463 float hfmax = -2000;
3464
3465 for (int x = 0; x < heightmapWidthSamples; x++)
3466 {
3467 for (int y = 0; y < heightmapHeightSamples; y++)
3468 {
3469 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3470 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3471
3472
3473 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3474 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3475
3476 hfmin = (val < hfmin) ? val : hfmin;
3477 hfmax = (val > hfmax) ? val : hfmax;
3478 }
3479 }
3480
3481
3482
3483
3484 lock (OdeLock)
3485 {
3486 IntPtr GroundGeom = IntPtr.Zero;
3487 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3488 {
3489 RegionTerrain.Remove(pOffset);
3490 if (GroundGeom != IntPtr.Zero)
3491 {
3492 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3493 {
3494 TerrainHeightFieldHeights.Remove(GroundGeom);
3495 }
3496 d.SpaceRemove(space, GroundGeom);
3497 d.GeomDestroy(GroundGeom);
3498 }
3499
3500 }
3501 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3502 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3503 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3504 offset, thickness, wrap);
3505 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3506 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3507 if (GroundGeom != IntPtr.Zero)
3508 {
3509 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3510 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3511
3512 }
3513 geom_name_map[GroundGeom] = "Terrain";
3514
3515 d.Matrix3 R = new d.Matrix3();
3516
3517 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3518 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3519 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3520
3521 q1 = q1 * q2;
3522 //q1 = q1 * q3;
3523 Vector3 v3;
3524 float angle;
3525 q1.GetAxisAngle(out v3, out angle);
3526
3527 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3528 d.GeomSetRotation(GroundGeom, ref R);
3529 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)) - 1, (pOffset.Y + ((int)Constants.RegionSize * 0.5f)) - 1, 0);
3530 IntPtr testGround = IntPtr.Zero;
3531 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3532 {
3533 RegionTerrain.Remove(pOffset);
3534 }
3535 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3536 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3537
3538 }
3539 }
3540
3541 public override void DeleteTerrain()
3542 {
3543 }
3544
3545 public float GetWaterLevel()
3546 {
3547 return waterlevel;
3548 }
3549
3550 public override bool SupportsCombining()
3551 {
3552 return true;
3553 }
3554
3555 public override void UnCombine(PhysicsScene pScene)
3556 {
3557 IntPtr localGround = IntPtr.Zero;
3558// float[] localHeightfield;
3559 bool proceed = false;
3560 List<IntPtr> geomDestroyList = new List<IntPtr>();
3561
3562 lock (OdeLock)
3563 {
3564 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3565 {
3566 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3567 {
3568 if (geom == localGround)
3569 {
3570// localHeightfield = TerrainHeightFieldHeights[geom];
3571 proceed = true;
3572 }
3573 else
3574 {
3575 geomDestroyList.Add(geom);
3576 }
3577 }
3578
3579 if (proceed)
3580 {
3581 m_worldOffset = Vector3.Zero;
3582 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3583 m_parentScene = null;
3584
3585 foreach (IntPtr g in geomDestroyList)
3586 {
3587 // removingHeightField needs to be done or the garbage collector will
3588 // collect the terrain data before we tell ODE to destroy it causing
3589 // memory corruption
3590 if (TerrainHeightFieldHeights.ContainsKey(g))
3591 {
3592// float[] removingHeightField = TerrainHeightFieldHeights[g];
3593 TerrainHeightFieldHeights.Remove(g);
3594
3595 if (RegionTerrain.ContainsKey(g))
3596 {
3597 RegionTerrain.Remove(g);
3598 }
3599
3600 d.GeomDestroy(g);
3601 //removingHeightField = new float[0];
3602 }
3603 }
3604
3605 }
3606 else
3607 {
3608 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3609
3610 }
3611 }
3612 }
3613 }
3614
3615 public override void SetWaterLevel(float baseheight)
3616 {
3617 waterlevel = baseheight;
3618 randomizeWater(waterlevel);
3619 }
3620
3621 public void randomizeWater(float baseheight)
3622 {
3623 const uint heightmapWidth = m_regionWidth + 2;
3624 const uint heightmapHeight = m_regionHeight + 2;
3625 const uint heightmapWidthSamples = m_regionWidth + 2;
3626 const uint heightmapHeightSamples = m_regionHeight + 2;
3627 const float scale = 1.0f;
3628 const float offset = 0.0f;
3629 const float thickness = 2.9f;
3630 const int wrap = 0;
3631
3632 for (int i = 0; i < (258 * 258); i++)
3633 {
3634 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3635 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3636 }
3637
3638 lock (OdeLock)
3639 {
3640 if (WaterGeom != IntPtr.Zero)
3641 {
3642 d.SpaceRemove(space, WaterGeom);
3643 }
3644 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3645 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3646 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3647 offset, thickness, wrap);
3648 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3649 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3650 if (WaterGeom != IntPtr.Zero)
3651 {
3652 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3653 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3654
3655 }
3656 geom_name_map[WaterGeom] = "Water";
3657
3658 d.Matrix3 R = new d.Matrix3();
3659
3660 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3661 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3662 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3663
3664 q1 = q1 * q2;
3665 //q1 = q1 * q3;
3666 Vector3 v3;
3667 float angle;
3668 q1.GetAxisAngle(out v3, out angle);
3669
3670 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3671 d.GeomSetRotation(WaterGeom, ref R);
3672 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3673
3674 }
3675
3676 }
3677
3678 public override void Dispose()
3679 {
3680 m_rayCastManager.Dispose();
3681 m_rayCastManager = null;
3682
3683 lock (OdeLock)
3684 {
3685 lock (_prims)
3686 {
3687 foreach (OdePrim prm in _prims)
3688 {
3689 RemovePrim(prm);
3690 }
3691 }
3692
3693 //foreach (OdeCharacter act in _characters)
3694 //{
3695 //RemoveAvatar(act);
3696 //}
3697 d.WorldDestroy(world);
3698 //d.CloseODE();
3699 }
3700 }
3701 public override Dictionary<uint, float> GetTopColliders()
3702 {
3703 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3704 int cnt = 0;
3705 lock (_prims)
3706 {
3707 foreach (OdePrim prm in _prims)
3708 {
3709 if (prm.CollisionScore > 0)
3710 {
3711 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3712 cnt++;
3713 prm.CollisionScore = 0f;
3714 if (cnt > 25)
3715 {
3716 break;
3717 }
3718 }
3719 }
3720 }
3721 return returncolliders;
3722 }
3723
3724 public override bool SupportsRayCast()
3725 {
3726 return true;
3727 }
3728
3729 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3730 {
3731 if (retMethod != null)
3732 {
3733 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3734 }
3735 }
3736
3737#if USE_DRAWSTUFF
3738 // Keyboard callback
3739 public void command(int cmd)
3740 {
3741 IntPtr geom;
3742 d.Mass mass;
3743 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3744
3745
3746
3747 Char ch = Char.ToLower((Char)cmd);
3748 switch ((Char)ch)
3749 {
3750 case 'w':
3751 try
3752 {
3753 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3754
3755 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3756 ds.SetViewpoint(ref xyz, ref hpr);
3757 }
3758 catch (ArgumentException)
3759 { hpr.X = 0; }
3760 break;
3761
3762 case 'a':
3763 hpr.X++;
3764 ds.SetViewpoint(ref xyz, ref hpr);
3765 break;
3766
3767 case 's':
3768 try
3769 {
3770 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3771
3772 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3773 ds.SetViewpoint(ref xyz, ref hpr);
3774 }
3775 catch (ArgumentException)
3776 { hpr.X = 0; }
3777 break;
3778 case 'd':
3779 hpr.X--;
3780 ds.SetViewpoint(ref xyz, ref hpr);
3781 break;
3782 case 'r':
3783 xyz.Z++;
3784 ds.SetViewpoint(ref xyz, ref hpr);
3785 break;
3786 case 'f':
3787 xyz.Z--;
3788 ds.SetViewpoint(ref xyz, ref hpr);
3789 break;
3790 case 'e':
3791 xyz.Y++;
3792 ds.SetViewpoint(ref xyz, ref hpr);
3793 break;
3794 case 'q':
3795 xyz.Y--;
3796 ds.SetViewpoint(ref xyz, ref hpr);
3797 break;
3798 }
3799 }
3800
3801 public void step(int pause)
3802 {
3803
3804 ds.SetColor(1.0f, 1.0f, 0.0f);
3805 ds.SetTexture(ds.Texture.Wood);
3806 lock (_prims)
3807 {
3808 foreach (OdePrim prm in _prims)
3809 {
3810 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3811 if (prm.prim_geom != IntPtr.Zero)
3812 {
3813 d.Vector3 pos;
3814 d.GeomCopyPosition(prm.prim_geom, out pos);
3815 //d.BodyCopyPosition(body, out pos);
3816
3817 d.Matrix3 R;
3818 d.GeomCopyRotation(prm.prim_geom, out R);
3819 //d.BodyCopyRotation(body, out R);
3820
3821
3822 d.Vector3 sides = new d.Vector3();
3823 sides.X = prm.Size.X;
3824 sides.Y = prm.Size.Y;
3825 sides.Z = prm.Size.Z;
3826
3827 ds.DrawBox(ref pos, ref R, ref sides);
3828 }
3829 }
3830 }
3831 ds.SetColor(1.0f, 0.0f, 0.0f);
3832 lock (_characters)
3833 {
3834 foreach (OdeCharacter chr in _characters)
3835 {
3836 if (chr.Shell != IntPtr.Zero)
3837 {
3838 IntPtr body = d.GeomGetBody(chr.Shell);
3839
3840 d.Vector3 pos;
3841 d.GeomCopyPosition(chr.Shell, out pos);
3842 //d.BodyCopyPosition(body, out pos);
3843
3844 d.Matrix3 R;
3845 d.GeomCopyRotation(chr.Shell, out R);
3846 //d.BodyCopyRotation(body, out R);
3847
3848 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3849 d.Vector3 sides = new d.Vector3();
3850 sides.X = 0.5f;
3851 sides.Y = 0.5f;
3852 sides.Z = 0.5f;
3853
3854 ds.DrawBox(ref pos, ref R, ref sides);
3855 }
3856 }
3857 }
3858 }
3859
3860 public void start(int unused)
3861 {
3862 ds.SetViewpoint(ref xyz, ref hpr);
3863 }
3864#endif
3865 }
3866} \ No newline at end of file