aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs3827
1 files changed, 7 insertions, 3820 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index a0101af..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,3810 +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 PhysicsActor result;
1774 IMesh mesh = null;
1775
1776 if (needsMeshing(pbs))
1777 {
1778 try
1779 {
1780 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1781 }
1782 catch(Exception e)
1783 {
1784 m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName);
1785 m_log.Debug(e.ToString());
1786 mesh = null;
1787 return null;
1788 }
1789 }
1790
1791 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1792
1793 return result;
1794 }
1795
1796 public override float TimeDilation
1797 {
1798 get { return m_timeDilation; }
1799 }
1800
1801 public override bool SupportsNINJAJoints
1802 {
1803 get { return m_NINJA_physics_joints_enabled; }
1804 }
1805
1806 // internal utility function: must be called within a lock (OdeLock)
1807 private void InternalAddActiveJoint(PhysicsJoint joint)
1808 {
1809 activeJoints.Add(joint);
1810 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1811 }
1812
1813 // internal utility function: must be called within a lock (OdeLock)
1814 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1815 {
1816 pendingJoints.Add(joint);
1817 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1818 }
1819
1820 // internal utility function: must be called within a lock (OdeLock)
1821 private void InternalRemovePendingJoint(PhysicsJoint joint)
1822 {
1823 pendingJoints.Remove(joint);
1824 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1825 }
1826
1827 // internal utility function: must be called within a lock (OdeLock)
1828 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1829 {
1830 activeJoints.Remove(joint);
1831 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1832 }
1833
1834 public override void DumpJointInfo()
1835 {
1836 string hdr = "[NINJA] JOINTINFO: ";
1837 foreach (PhysicsJoint j in pendingJoints)
1838 {
1839 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1840 }
1841 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1842 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1843 {
1844 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1845 }
1846 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1847 foreach (PhysicsJoint j in activeJoints)
1848 {
1849 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1850 }
1851 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1852 foreach (string jointName in SOPName_to_activeJoint.Keys)
1853 {
1854 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1855 }
1856 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1857
1858 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1859 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1860 foreach (string actorName in joints_connecting_actor.Keys)
1861 {
1862 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1863 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1864 {
1865 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1866 }
1867 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1868 }
1869 }
1870
1871 public override void RequestJointDeletion(string ObjectNameInScene)
1872 {
1873 lock (externalJointRequestsLock)
1874 {
1875 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1876 {
1877 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1878 }
1879 }
1880 }
1881
1882 private void DeleteRequestedJoints()
1883 {
1884 List<string> myRequestedJointsToBeDeleted;
1885 lock (externalJointRequestsLock)
1886 {
1887 // make a local copy of the shared list for processing (threading issues)
1888 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1889 }
1890
1891 foreach (string jointName in myRequestedJointsToBeDeleted)
1892 {
1893 lock (OdeLock)
1894 {
1895 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1896 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1897 {
1898 OdePhysicsJoint joint = null;
1899 if (SOPName_to_activeJoint.ContainsKey(jointName))
1900 {
1901 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1902 InternalRemoveActiveJoint(joint);
1903 }
1904 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1905 {
1906 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1907 InternalRemovePendingJoint(joint);
1908 }
1909
1910 if (joint != null)
1911 {
1912 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1913 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1914 {
1915 string bodyName = joint.BodyNames[iBodyName];
1916 if (bodyName != "NULL")
1917 {
1918 joints_connecting_actor[bodyName].Remove(joint);
1919 if (joints_connecting_actor[bodyName].Count == 0)
1920 {
1921 joints_connecting_actor.Remove(bodyName);
1922 }
1923 }
1924 }
1925
1926 DoJointDeactivated(joint);
1927 if (joint.jointID != IntPtr.Zero)
1928 {
1929 d.JointDestroy(joint.jointID);
1930 joint.jointID = IntPtr.Zero;
1931 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1932 }
1933 else
1934 {
1935 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1936 }
1937 }
1938 else
1939 {
1940 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1941 }
1942 }
1943 else
1944 {
1945 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1946 }
1947 }
1948 }
1949
1950 // remove processed joints from the shared list
1951 lock (externalJointRequestsLock)
1952 {
1953 foreach (string jointName in myRequestedJointsToBeDeleted)
1954 {
1955 requestedJointsToBeDeleted.Remove(jointName);
1956 }
1957 }
1958 }
1959
1960 // for pending joints we don't know if their associated bodies exist yet or not.
1961 // the joint is actually created during processing of the taints
1962 private void CreateRequestedJoints()
1963 {
1964 List<PhysicsJoint> myRequestedJointsToBeCreated;
1965 lock (externalJointRequestsLock)
1966 {
1967 // make a local copy of the shared list for processing (threading issues)
1968 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1969 }
1970
1971 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1972 {
1973 lock (OdeLock)
1974 {
1975 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1976 {
1977 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);
1978 continue;
1979 }
1980 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1981 {
1982 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);
1983 continue;
1984 }
1985
1986 InternalAddPendingJoint(joint as OdePhysicsJoint);
1987
1988 if (joint.BodyNames.Count >= 2)
1989 {
1990 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1991 {
1992 string bodyName = joint.BodyNames[iBodyName];
1993 if (bodyName != "NULL")
1994 {
1995 if (!joints_connecting_actor.ContainsKey(bodyName))
1996 {
1997 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1998 }
1999 joints_connecting_actor[bodyName].Add(joint);
2000 }
2001 }
2002 }
2003 }
2004 }
2005
2006 // remove processed joints from shared list
2007 lock (externalJointRequestsLock)
2008 {
2009 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2010 {
2011 requestedJointsToBeCreated.Remove(joint);
2012 }
2013 }
2014
2015 }
2016
2017 // public function to add an request for joint creation
2018 // this joint will just be added to a waiting list that is NOT processed during the main
2019 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2020
2021 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2022 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2023
2024 {
2025
2026 OdePhysicsJoint joint = new OdePhysicsJoint();
2027 joint.ObjectNameInScene = objectNameInScene;
2028 joint.Type = jointType;
2029 joint.Position = position;
2030 joint.Rotation = rotation;
2031 joint.RawParams = parms;
2032 joint.BodyNames = new List<string>(bodyNames);
2033 joint.TrackedBodyName = trackedBodyName;
2034 joint.LocalRotation = localRotation;
2035 joint.jointID = IntPtr.Zero;
2036 joint.ErrorMessageCount = 0;
2037
2038 lock (externalJointRequestsLock)
2039 {
2040 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2041 {
2042 requestedJointsToBeCreated.Add(joint);
2043 }
2044 }
2045 return joint;
2046 }
2047
2048 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2049 {
2050 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2051 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2052 {
2053
2054 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2055 //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)
2056 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2057 {
2058 jointsToRemove.Add(j);
2059 }
2060 foreach (PhysicsJoint j in jointsToRemove)
2061 {
2062 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2063 RequestJointDeletion(j.ObjectNameInScene);
2064 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2065 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)
2066 }
2067 }
2068 }
2069
2070 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2071 {
2072 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2073 lock (OdeLock)
2074 {
2075 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2076 RemoveAllJointsConnectedToActor(actor);
2077 }
2078 }
2079
2080 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2081 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2082 {
2083 Debug.Assert(joint.IsInPhysicsEngine);
2084 d.Vector3 pos = new d.Vector3();
2085
2086 if (!(joint is OdePhysicsJoint))
2087 {
2088 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2089 }
2090 else
2091 {
2092 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2093 switch (odeJoint.Type)
2094 {
2095 case PhysicsJointType.Ball:
2096 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2097 break;
2098 case PhysicsJointType.Hinge:
2099 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2100 break;
2101 }
2102 }
2103 return new Vector3(pos.X, pos.Y, pos.Z);
2104 }
2105
2106 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2107 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2108 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2109 // keeping track of the joint's original orientation relative to one of the involved bodies.
2110 public override Vector3 GetJointAxis(PhysicsJoint joint)
2111 {
2112 Debug.Assert(joint.IsInPhysicsEngine);
2113 d.Vector3 axis = new d.Vector3();
2114
2115 if (!(joint is OdePhysicsJoint))
2116 {
2117 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2118 }
2119 else
2120 {
2121 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2122 switch (odeJoint.Type)
2123 {
2124 case PhysicsJointType.Ball:
2125 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2126 break;
2127 case PhysicsJointType.Hinge:
2128 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2129 break;
2130 }
2131 }
2132 return new Vector3(axis.X, axis.Y, axis.Z);
2133 }
2134
2135
2136 public void remActivePrim(OdePrim deactivatePrim)
2137 {
2138 lock (_activeprims)
2139 {
2140 _activeprims.Remove(deactivatePrim);
2141 }
2142 }
2143
2144 public override void RemovePrim(PhysicsActor prim)
2145 {
2146 if (prim is OdePrim)
2147 {
2148 lock (OdeLock)
2149 {
2150 OdePrim p = (OdePrim) prim;
2151
2152 p.setPrimForRemoval();
2153 AddPhysicsActorTaint(prim);
2154 //RemovePrimThreadLocked(p);
2155 }
2156 }
2157 }
2158
2159 /// <summary>
2160 /// This is called from within simulate but outside the locked portion
2161 /// We need to do our own locking here
2162 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2163 ///
2164 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2165 /// that the space was using.
2166 /// </summary>
2167 /// <param name="prim"></param>
2168 public void RemovePrimThreadLocked(OdePrim prim)
2169 {
2170//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2171 lock (prim)
2172 {
2173 remCollisionEventReporting(prim);
2174 lock (ode)
2175 {
2176 if (prim.prim_geom != IntPtr.Zero)
2177 {
2178 prim.ResetTaints();
2179
2180 if (prim.IsPhysical)
2181 {
2182 prim.disableBody();
2183 if (prim.childPrim)
2184 {
2185 prim.childPrim = false;
2186 prim.Body = IntPtr.Zero;
2187 prim.m_disabled = true;
2188 prim.IsPhysical = false;
2189 }
2190
2191
2192 }
2193 // we don't want to remove the main space
2194
2195 // If the geometry is in the targetspace, remove it from the target space
2196 //m_log.Warn(prim.m_targetSpace);
2197
2198 //if (prim.m_targetSpace != IntPtr.Zero)
2199 //{
2200 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2201 //{
2202
2203 //if (d.GeomIsSpace(prim.m_targetSpace))
2204 //{
2205 //waitForSpaceUnlock(prim.m_targetSpace);
2206 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2207 prim.m_targetSpace = IntPtr.Zero;
2208 //}
2209 //else
2210 //{
2211 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2212 //((OdePrim)prim).m_targetSpace.ToString());
2213 //}
2214
2215 //}
2216 //}
2217 //m_log.Warn(prim.prim_geom);
2218 try
2219 {
2220 if (prim.prim_geom != IntPtr.Zero)
2221 {
2222 d.GeomDestroy(prim.prim_geom);
2223 prim.prim_geom = IntPtr.Zero;
2224 }
2225 else
2226 {
2227 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2228 }
2229 }
2230 catch (AccessViolationException)
2231 {
2232 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2233 }
2234 lock (_prims)
2235 _prims.Remove(prim);
2236
2237 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2238 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2239 //{
2240 //if (prim.m_targetSpace != null)
2241 //{
2242 //if (d.GeomIsSpace(prim.m_targetSpace))
2243 //{
2244 //waitForSpaceUnlock(prim.m_targetSpace);
2245 //d.SpaceRemove(space, prim.m_targetSpace);
2246 // free up memory used by the space.
2247 //d.SpaceDestroy(prim.m_targetSpace);
2248 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2249 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2250 //}
2251 //else
2252 //{
2253 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2254 //((OdePrim) prim).m_targetSpace.ToString());
2255 //}
2256 //}
2257 //}
2258
2259 if (SupportsNINJAJoints)
2260 {
2261 RemoveAllJointsConnectedToActorThreadLocked(prim);
2262 }
2263 }
2264 }
2265 }
2266 }
2267
2268 #endregion
2269
2270 #region Space Separation Calculation
2271
2272 /// <summary>
2273 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2274 /// </summary>
2275 /// <param name="pSpace"></param>
2276 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2277 {
2278 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2279 {
2280 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2281 {
2282 if (staticPrimspace[x, y] == pSpace)
2283 staticPrimspace[x, y] = IntPtr.Zero;
2284 }
2285 }
2286 }
2287
2288 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2289 {
2290 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2291 }
2292
2293 /// <summary>
2294 /// Called when a static prim moves. Allocates a space for the prim based on its position
2295 /// </summary>
2296 /// <param name="geom">the pointer to the geom that moved</param>
2297 /// <param name="pos">the position that the geom moved to</param>
2298 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2299 /// <returns>a pointer to the new space it's in</returns>
2300 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2301 {
2302 // Called from setting the Position and Size of an ODEPrim so
2303 // it's already in locked space.
2304
2305 // we don't want to remove the main space
2306 // we don't need to test physical here because this function should
2307 // never be called if the prim is physical(active)
2308
2309 // All physical prim end up in the root space
2310 //Thread.Sleep(20);
2311 if (currentspace != space)
2312 {
2313 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2314 //if (currentspace == IntPtr.Zero)
2315 //{
2316 //int adfadf = 0;
2317 //}
2318 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2319 {
2320 if (d.GeomIsSpace(currentspace))
2321 {
2322 waitForSpaceUnlock(currentspace);
2323 d.SpaceRemove(currentspace, geom);
2324 }
2325 else
2326 {
2327 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2328 " Geom:" + geom);
2329 }
2330 }
2331 else
2332 {
2333 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2334 if (sGeomIsIn != IntPtr.Zero)
2335 {
2336 if (d.GeomIsSpace(currentspace))
2337 {
2338 waitForSpaceUnlock(sGeomIsIn);
2339 d.SpaceRemove(sGeomIsIn, geom);
2340 }
2341 else
2342 {
2343 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2344 sGeomIsIn + " Geom:" + geom);
2345 }
2346 }
2347 }
2348
2349 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2350 if (d.SpaceGetNumGeoms(currentspace) == 0)
2351 {
2352 if (currentspace != IntPtr.Zero)
2353 {
2354 if (d.GeomIsSpace(currentspace))
2355 {
2356 waitForSpaceUnlock(currentspace);
2357 waitForSpaceUnlock(space);
2358 d.SpaceRemove(space, currentspace);
2359 // free up memory used by the space.
2360
2361 //d.SpaceDestroy(currentspace);
2362 resetSpaceArrayItemToZero(currentspace);
2363 }
2364 else
2365 {
2366 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2367 currentspace + " Geom:" + geom);
2368 }
2369 }
2370 }
2371 }
2372 else
2373 {
2374 // this is a physical object that got disabled. ;.;
2375 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2376 {
2377 if (d.SpaceQuery(currentspace, geom))
2378 {
2379 if (d.GeomIsSpace(currentspace))
2380 {
2381 waitForSpaceUnlock(currentspace);
2382 d.SpaceRemove(currentspace, geom);
2383 }
2384 else
2385 {
2386 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2387 currentspace + " Geom:" + geom);
2388 }
2389 }
2390 else
2391 {
2392 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2393 if (sGeomIsIn != IntPtr.Zero)
2394 {
2395 if (d.GeomIsSpace(sGeomIsIn))
2396 {
2397 waitForSpaceUnlock(sGeomIsIn);
2398 d.SpaceRemove(sGeomIsIn, geom);
2399 }
2400 else
2401 {
2402 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2403 sGeomIsIn + " Geom:" + geom);
2404 }
2405 }
2406 }
2407 }
2408 }
2409
2410 // The routines in the Position and Size sections do the 'inserting' into the space,
2411 // so all we have to do is make sure that the space that we're putting the prim into
2412 // is in the 'main' space.
2413 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2414 IntPtr newspace = calculateSpaceForGeom(pos);
2415
2416 if (newspace == IntPtr.Zero)
2417 {
2418 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2419 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2420 }
2421
2422 return newspace;
2423 }
2424
2425 /// <summary>
2426 /// Creates a new space at X Y
2427 /// </summary>
2428 /// <param name="iprimspaceArrItemX"></param>
2429 /// <param name="iprimspaceArrItemY"></param>
2430 /// <returns>A pointer to the created space</returns>
2431 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2432 {
2433 // creating a new space for prim and inserting it into main space.
2434 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2435 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2436 waitForSpaceUnlock(space);
2437 d.SpaceSetSublevel(space, 1);
2438 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2439 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2440 }
2441
2442 /// <summary>
2443 /// Calculates the space the prim should be in by its position
2444 /// </summary>
2445 /// <param name="pos"></param>
2446 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2447 public IntPtr calculateSpaceForGeom(Vector3 pos)
2448 {
2449 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2450 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2451 return staticPrimspace[xyspace[0], xyspace[1]];
2452 }
2453
2454 /// <summary>
2455 /// Holds the space allocation logic
2456 /// </summary>
2457 /// <param name="pos"></param>
2458 /// <returns>an array item based on the position</returns>
2459 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2460 {
2461 int[] returnint = new int[2];
2462
2463 returnint[0] = (int) (pos.X/metersInSpace);
2464
2465 if (returnint[0] > ((int) (259f/metersInSpace)))
2466 returnint[0] = ((int) (259f/metersInSpace));
2467 if (returnint[0] < 0)
2468 returnint[0] = 0;
2469
2470 returnint[1] = (int) (pos.Y/metersInSpace);
2471 if (returnint[1] > ((int) (259f/metersInSpace)))
2472 returnint[1] = ((int) (259f/metersInSpace));
2473 if (returnint[1] < 0)
2474 returnint[1] = 0;
2475
2476 return returnint;
2477 }
2478
2479 #endregion
2480
2481 /// <summary>
2482 /// Routine to figure out if we need to mesh this prim with our mesher
2483 /// </summary>
2484 /// <param name="pbs"></param>
2485 /// <returns></returns>
2486 public bool needsMeshing(PrimitiveBaseShape pbs)
2487 {
2488 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2489 // but we still need to check for sculptie meshing being enabled so this is the most
2490 // convenient place to do it for now...
2491
2492 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2493 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2494 int iPropertiesNotSupportedDefault = 0;
2495
2496 if (pbs.SculptEntry && !meshSculptedPrim)
2497 {
2498#if SPAM
2499 m_log.Warn("NonMesh");
2500#endif
2501 return false;
2502 }
2503
2504 // 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
2505 if (!forceSimplePrimMeshing)
2506 {
2507 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2508 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2509 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2510 {
2511
2512 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2513 && pbs.ProfileHollow == 0
2514 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2515 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2516 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2517 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2518 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2519 {
2520#if SPAM
2521 m_log.Warn("NonMesh");
2522#endif
2523 return false;
2524 }
2525 }
2526 }
2527
2528 if (pbs.ProfileHollow != 0)
2529 iPropertiesNotSupportedDefault++;
2530
2531 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2532 iPropertiesNotSupportedDefault++;
2533
2534 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2535 iPropertiesNotSupportedDefault++;
2536
2537 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2538 iPropertiesNotSupportedDefault++;
2539
2540 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2541 iPropertiesNotSupportedDefault++;
2542
2543 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2544 iPropertiesNotSupportedDefault++;
2545
2546 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2547 iPropertiesNotSupportedDefault++;
2548
2549 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))
2550 iPropertiesNotSupportedDefault++;
2551
2552 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2553 iPropertiesNotSupportedDefault++;
2554
2555 // test for torus
2556 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2557 {
2558 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2559 {
2560 iPropertiesNotSupportedDefault++;
2561 }
2562 }
2563 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2564 {
2565 if (pbs.PathCurve == (byte)Extrusion.Straight)
2566 {
2567 iPropertiesNotSupportedDefault++;
2568 }
2569
2570 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2571 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2572 {
2573 iPropertiesNotSupportedDefault++;
2574 }
2575 }
2576 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2577 {
2578 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2579 {
2580 iPropertiesNotSupportedDefault++;
2581 }
2582 }
2583 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2584 {
2585 if (pbs.PathCurve == (byte)Extrusion.Straight)
2586 {
2587 iPropertiesNotSupportedDefault++;
2588 }
2589 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2590 {
2591 iPropertiesNotSupportedDefault++;
2592 }
2593 }
2594
2595
2596 if (iPropertiesNotSupportedDefault == 0)
2597 {
2598#if SPAM
2599 m_log.Warn("NonMesh");
2600#endif
2601 return false;
2602 }
2603#if SPAM
2604 m_log.Debug("Mesh");
2605#endif
2606 return true;
2607 }
2608
2609 /// <summary>
2610 /// Called after our prim properties are set Scale, position etc.
2611 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2612 /// This assures us that we have no race conditions
2613 /// </summary>
2614 /// <param name="prim"></param>
2615 public override void AddPhysicsActorTaint(PhysicsActor prim)
2616 {
2617
2618 if (prim is OdePrim)
2619 {
2620 OdePrim taintedprim = ((OdePrim) prim);
2621 lock (_taintedPrimLock)
2622 {
2623 if (!(_taintedPrimH.Contains(taintedprim)))
2624 {
2625//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2626 _taintedPrimH.Add(taintedprim); // HashSet for searching
2627 _taintedPrimL.Add(taintedprim); // List for ordered readout
2628 }
2629 }
2630 return;
2631 }
2632 else if (prim is OdeCharacter)
2633 {
2634 OdeCharacter taintedchar = ((OdeCharacter)prim);
2635 lock (_taintedActors)
2636 {
2637 if (!(_taintedActors.Contains(taintedchar)))
2638 {
2639 _taintedActors.Add(taintedchar);
2640 if (taintedchar.bad)
2641 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2642 }
2643 }
2644 }
2645 }
2646
2647 /// <summary>
2648 /// This is our main simulate loop
2649 /// It's thread locked by a Mutex in the scene.
2650 /// It holds Collisions, it instructs ODE to step through the physical reactions
2651 /// It moves the objects around in memory
2652 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2653 /// </summary>
2654 /// <param name="timeStep"></param>
2655 /// <returns></returns>
2656 public override float Simulate(float timeStep)
2657 {
2658 if (framecount >= int.MaxValue)
2659 framecount = 0;
2660
2661 //if (m_worldOffset != Vector3.Zero)
2662 // return 0;
2663
2664 framecount++;
2665
2666 float fps = 0;
2667 //m_log.Info(timeStep.ToString());
2668 step_time += timeStep;
2669
2670 // If We're loaded down by something else,
2671 // or debugging with the Visual Studio project on pause
2672 // skip a few frames to catch up gracefully.
2673 // without shooting the physicsactors all over the place
2674
2675 if (step_time >= m_SkipFramesAtms)
2676 {
2677 // Instead of trying to catch up, it'll do 5 physics frames only
2678 step_time = ODE_STEPSIZE;
2679 m_physicsiterations = 5;
2680 }
2681 else
2682 {
2683 m_physicsiterations = 10;
2684 }
2685
2686 if (SupportsNINJAJoints)
2687 {
2688 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2689 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2690 }
2691
2692 lock (OdeLock)
2693 {
2694 // Process 10 frames if the sim is running normal..
2695 // process 5 frames if the sim is running slow
2696 //try
2697 //{
2698 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2699 //}
2700 //catch (StackOverflowException)
2701 //{
2702 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2703 // ode.drelease(world);
2704 //base.TriggerPhysicsBasedRestart();
2705 //}
2706
2707 int i = 0;
2708
2709 // Figure out the Frames Per Second we're going at.
2710 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2711
2712 fps = (step_time / ODE_STEPSIZE) * 1000;
2713 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2714 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2715
2716 step_time = 0.09375f;
2717
2718 while (step_time > 0.0f)
2719 {
2720 //lock (ode)
2721 //{
2722 //if (!ode.lockquery())
2723 //{
2724 // ode.dlock(world);
2725 try
2726 {
2727 // Insert, remove Characters
2728 bool processedtaints = false;
2729
2730 lock (_taintedActors)
2731 {
2732 if (_taintedActors.Count > 0)
2733 {
2734 foreach (OdeCharacter character in _taintedActors)
2735 {
2736
2737 character.ProcessTaints(timeStep);
2738
2739 processedtaints = true;
2740 //character.m_collisionscore = 0;
2741 }
2742
2743 if (processedtaints)
2744 _taintedActors.Clear();
2745 }
2746 }
2747
2748 // Modify other objects in the scene.
2749 processedtaints = false;
2750
2751 lock (_taintedPrimLock)
2752 {
2753 foreach (OdePrim prim in _taintedPrimL)
2754 {
2755 if (prim.m_taintremove)
2756 {
2757 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2758 RemovePrimThreadLocked(prim);
2759 }
2760 else
2761 {
2762 //Console.WriteLine("Simulate calls ProcessTaints");
2763 prim.ProcessTaints(timeStep);
2764 }
2765 processedtaints = true;
2766 prim.m_collisionscore = 0;
2767
2768 // This loop can block up the Heartbeat for a very long time on large regions.
2769 // We need to let the Watchdog know that the Heartbeat is not dead
2770 // NOTE: This is currently commented out, but if things like OAR loading are
2771 // timing the heartbeat out we will need to uncomment it
2772 //Watchdog.UpdateThread();
2773 }
2774
2775 if (SupportsNINJAJoints)
2776 {
2777 // Create pending joints, if possible
2778
2779 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2780 // a joint requires specifying the body id of both involved bodies
2781 if (pendingJoints.Count > 0)
2782 {
2783 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2784 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2785 foreach (PhysicsJoint joint in pendingJoints)
2786 {
2787 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2788 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2789 List<IntPtr> jointBodies = new List<IntPtr>();
2790 bool allJointBodiesAreReady = true;
2791 foreach (string jointParam in jointParams)
2792 {
2793 if (jointParam == "NULL")
2794 {
2795 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2796 jointBodies.Add(IntPtr.Zero);
2797 }
2798 else
2799 {
2800 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2801 bool foundPrim = false;
2802 lock (_prims)
2803 {
2804 foreach (OdePrim prim in _prims) // FIXME: inefficient
2805 {
2806 if (prim.SOPName == jointParam)
2807 {
2808 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2809 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2810 {
2811 jointBodies.Add(prim.Body);
2812 foundPrim = true;
2813 break;
2814 }
2815 else
2816 {
2817 DoJointErrorMessage(joint, "prim name " + jointParam +
2818 " exists but is not (yet) physical; deferring joint creation. " +
2819 "IsPhysical property is " + prim.IsPhysical +
2820 " and body is " + prim.Body);
2821 foundPrim = false;
2822 break;
2823 }
2824 }
2825 }
2826 }
2827 if (foundPrim)
2828 {
2829 // all is fine
2830 }
2831 else
2832 {
2833 allJointBodiesAreReady = false;
2834 break;
2835 }
2836 }
2837 }
2838 if (allJointBodiesAreReady)
2839 {
2840 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2841 if (jointBodies[0] == jointBodies[1])
2842 {
2843 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2844 }
2845 else
2846 {
2847 switch (joint.Type)
2848 {
2849 case PhysicsJointType.Ball:
2850 {
2851 IntPtr odeJoint;
2852 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2853 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2854 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2855 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2856 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2857 d.JointSetBallAnchor(odeJoint,
2858 joint.Position.X,
2859 joint.Position.Y,
2860 joint.Position.Z);
2861 //DoJointErrorMessage(joint, "ODE joint setting OK");
2862 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2863 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2864 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2865 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2866
2867 if (joint is OdePhysicsJoint)
2868 {
2869 ((OdePhysicsJoint)joint).jointID = odeJoint;
2870 }
2871 else
2872 {
2873 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2874 }
2875 }
2876 break;
2877 case PhysicsJointType.Hinge:
2878 {
2879 IntPtr odeJoint;
2880 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2881 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2882 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2883 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2884 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2885 d.JointSetHingeAnchor(odeJoint,
2886 joint.Position.X,
2887 joint.Position.Y,
2888 joint.Position.Z);
2889 // We use the orientation of the x-axis of the joint's coordinate frame
2890 // as the axis for the hinge.
2891
2892 // Therefore, we must get the joint's coordinate frame based on the
2893 // joint.Rotation field, which originates from the orientation of the
2894 // joint's proxy object in the scene.
2895
2896 // The joint's coordinate frame is defined as the transformation matrix
2897 // that converts a vector from joint-local coordinates into world coordinates.
2898 // World coordinates are defined as the XYZ coordinate system of the sim,
2899 // as shown in the top status-bar of the viewer.
2900
2901 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2902 // and use that as the hinge axis.
2903
2904 //joint.Rotation.Normalize();
2905 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2906
2907 // Now extract the X axis of the joint's coordinate frame.
2908
2909 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2910 // tar pit of transposed, inverted, and generally messed-up orientations.
2911 // (In other words, Matrix4.AtAxis() is borked.)
2912 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2913
2914 // Instead, compute the X axis of the coordinate frame by transforming
2915 // the (1,0,0) vector. At least that works.
2916
2917 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2918 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2919 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2920 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2921 d.JointSetHingeAxis(odeJoint,
2922 jointAxis.X,
2923 jointAxis.Y,
2924 jointAxis.Z);
2925 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2926 if (joint is OdePhysicsJoint)
2927 {
2928 ((OdePhysicsJoint)joint).jointID = odeJoint;
2929 }
2930 else
2931 {
2932 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2933 }
2934 }
2935 break;
2936 }
2937 successfullyProcessedPendingJoints.Add(joint);
2938 }
2939 }
2940 else
2941 {
2942 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2943 }
2944 }
2945 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2946 {
2947 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2948 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2949 InternalRemovePendingJoint(successfullyProcessedJoint);
2950 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2951 InternalAddActiveJoint(successfullyProcessedJoint);
2952 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2953 }
2954 }
2955 }
2956
2957 if (processedtaints)
2958//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2959 _taintedPrimH.Clear();
2960 _taintedPrimL.Clear();
2961 }
2962
2963 // Move characters
2964 lock (_characters)
2965 {
2966 List<OdeCharacter> defects = new List<OdeCharacter>();
2967 foreach (OdeCharacter actor in _characters)
2968 {
2969 if (actor != null)
2970 actor.Move(timeStep, defects);
2971 }
2972 if (0 != defects.Count)
2973 {
2974 foreach (OdeCharacter defect in defects)
2975 {
2976 RemoveCharacter(defect);
2977 }
2978 }
2979 }
2980
2981 // Move other active objects
2982 lock (_activeprims)
2983 {
2984 foreach (OdePrim prim in _activeprims)
2985 {
2986 prim.m_collisionscore = 0;
2987 prim.Move(timeStep);
2988 }
2989 }
2990
2991 //if ((framecount % m_randomizeWater) == 0)
2992 // randomizeWater(waterlevel);
2993
2994 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2995 m_rayCastManager.ProcessQueuedRequests();
2996
2997 collision_optimized(timeStep);
2998
2999 lock (_collisionEventPrim)
3000 {
3001 foreach (PhysicsActor obj in _collisionEventPrim)
3002 {
3003 if (obj == null)
3004 continue;
3005
3006 switch ((ActorTypes)obj.PhysicsActorType)
3007 {
3008 case ActorTypes.Agent:
3009 OdeCharacter cobj = (OdeCharacter)obj;
3010 cobj.AddCollisionFrameTime(100);
3011 cobj.SendCollisions();
3012 break;
3013 case ActorTypes.Prim:
3014 OdePrim pobj = (OdePrim)obj;
3015 pobj.SendCollisions();
3016 break;
3017 }
3018 }
3019 }
3020
3021 //if (m_global_contactcount > 5)
3022 //{
3023 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3024 //}
3025
3026 m_global_contactcount = 0;
3027
3028 d.WorldQuickStep(world, ODE_STEPSIZE);
3029 d.JointGroupEmpty(contactgroup);
3030 //ode.dunlock(world);
3031 }
3032 catch (Exception e)
3033 {
3034 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3035 ode.dunlock(world);
3036 }
3037
3038 step_time -= ODE_STEPSIZE;
3039 i++;
3040 //}
3041 //else
3042 //{
3043 //fps = 0;
3044 //}
3045 //}
3046 }
3047
3048 lock (_characters)
3049 {
3050 foreach (OdeCharacter actor in _characters)
3051 {
3052 if (actor != null)
3053 {
3054 if (actor.bad)
3055 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3056 actor.UpdatePositionAndVelocity();
3057 }
3058 }
3059 }
3060
3061 lock (_badCharacter)
3062 {
3063 if (_badCharacter.Count > 0)
3064 {
3065 foreach (OdeCharacter chr in _badCharacter)
3066 {
3067 RemoveCharacter(chr);
3068 }
3069 _badCharacter.Clear();
3070 }
3071 }
3072
3073 lock (_activeprims)
3074 {
3075 //if (timeStep < 0.2f)
3076 {
3077 foreach (OdePrim actor in _activeprims)
3078 {
3079 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3080 {
3081 actor.UpdatePositionAndVelocity();
3082
3083 if (SupportsNINJAJoints)
3084 {
3085 // If an actor moved, move its joint proxy objects as well.
3086 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3087 // for this purpose but it is never called! So we just do the joint
3088 // movement code here.
3089
3090 if (actor.SOPName != null &&
3091 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3092 joints_connecting_actor[actor.SOPName] != null &&
3093 joints_connecting_actor[actor.SOPName].Count > 0)
3094 {
3095 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3096 {
3097 if (affectedJoint.IsInPhysicsEngine)
3098 {
3099 DoJointMoved(affectedJoint);
3100 }
3101 else
3102 {
3103 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);
3104 }
3105 }
3106 }
3107 }
3108 }
3109 }
3110 }
3111 }
3112
3113 //DumpJointInfo();
3114
3115 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3116 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3117 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3118 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3119 {
3120 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3121 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3122
3123 if (physics_logging_append_existing_logfile)
3124 {
3125 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3126 TextWriter fwriter = File.AppendText(fname);
3127 fwriter.WriteLine(header);
3128 fwriter.Close();
3129 }
3130 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3131 }
3132 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
3133
3134 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3135 // has a max of 100 ms to run theoretically.
3136 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3137 // If Physics stalls, it takes longer which makes the tick count ms larger.
3138
3139 if (latertickcount < 100)
3140 m_timeDilation = 1.0f;
3141 else
3142 {
3143 m_timeDilation = 100f / latertickcount;
3144 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3145 }
3146
3147 tickCountFrameRun = Util.EnvironmentTickCount();
3148 }
3149
3150 return fps;
3151 }
3152
3153 public override void GetResults()
3154 {
3155 }
3156
3157 public override bool IsThreaded
3158 {
3159 // for now we won't be multithreaded
3160 get { return (false); }
3161 }
3162
3163 #region ODE Specific Terrain Fixes
3164 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3165 {
3166 float[] returnarr = new float[262144];
3167 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3168
3169 // Filling out the array into its multi-dimensional components
3170 for (int y = 0; y < WorldExtents.Y; y++)
3171 {
3172 for (int x = 0; x < WorldExtents.X; x++)
3173 {
3174 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3175 }
3176 }
3177
3178 // Resize using Nearest Neighbour
3179
3180 // This particular way is quick but it only works on a multiple of the original
3181
3182 // The idea behind this method can be described with the following diagrams
3183 // second pass and third pass happen in the same loop really.. just separated
3184 // them to show what this does.
3185
3186 // First Pass
3187 // ResultArr:
3188 // 1,1,1,1,1,1
3189 // 1,1,1,1,1,1
3190 // 1,1,1,1,1,1
3191 // 1,1,1,1,1,1
3192 // 1,1,1,1,1,1
3193 // 1,1,1,1,1,1
3194
3195 // Second Pass
3196 // ResultArr2:
3197 // 1,,1,,1,,1,,1,,1,
3198 // ,,,,,,,,,,
3199 // 1,,1,,1,,1,,1,,1,
3200 // ,,,,,,,,,,
3201 // 1,,1,,1,,1,,1,,1,
3202 // ,,,,,,,,,,
3203 // 1,,1,,1,,1,,1,,1,
3204 // ,,,,,,,,,,
3205 // 1,,1,,1,,1,,1,,1,
3206 // ,,,,,,,,,,
3207 // 1,,1,,1,,1,,1,,1,
3208
3209 // Third pass fills in the blanks
3210 // ResultArr2:
3211 // 1,1,1,1,1,1,1,1,1,1,1,1
3212 // 1,1,1,1,1,1,1,1,1,1,1,1
3213 // 1,1,1,1,1,1,1,1,1,1,1,1
3214 // 1,1,1,1,1,1,1,1,1,1,1,1
3215 // 1,1,1,1,1,1,1,1,1,1,1,1
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
3223 // X,Y = .
3224 // X+1,y = ^
3225 // X,Y+1 = *
3226 // X+1,Y+1 = #
3227
3228 // Filling in like this;
3229 // .*
3230 // ^#
3231 // 1st .
3232 // 2nd *
3233 // 3rd ^
3234 // 4th #
3235 // on single loop.
3236
3237 float[,] resultarr2 = new float[512, 512];
3238 for (int y = 0; y < WorldExtents.Y; y++)
3239 {
3240 for (int x = 0; x < WorldExtents.X; x++)
3241 {
3242 resultarr2[y * 2, x * 2] = resultarr[y, x];
3243
3244 if (y < WorldExtents.Y)
3245 {
3246 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3247 }
3248 if (x < WorldExtents.X)
3249 {
3250 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3251 }
3252 if (x < WorldExtents.X && y < WorldExtents.Y)
3253 {
3254 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3255 }
3256 }
3257 }
3258
3259 //Flatten out the array
3260 int i = 0;
3261 for (int y = 0; y < 512; y++)
3262 {
3263 for (int x = 0; x < 512; x++)
3264 {
3265 if (resultarr2[y, x] <= 0)
3266 returnarr[i] = 0.0000001f;
3267 else
3268 returnarr[i] = resultarr2[y, x];
3269
3270 i++;
3271 }
3272 }
3273
3274 return returnarr;
3275 }
3276
3277 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3278 {
3279 float[] returnarr = new float[262144];
3280 float[,] resultarr = new float[512,512];
3281
3282 // Filling out the array into its multi-dimensional components
3283 for (int y = 0; y < 256; y++)
3284 {
3285 for (int x = 0; x < 256; x++)
3286 {
3287 resultarr[y, x] = heightMap[y * 256 + x];
3288 }
3289 }
3290
3291 // Resize using interpolation
3292
3293 // This particular way is quick but it only works on a multiple of the original
3294
3295 // The idea behind this method can be described with the following diagrams
3296 // second pass and third pass happen in the same loop really.. just separated
3297 // them to show what this does.
3298
3299 // First Pass
3300 // ResultArr:
3301 // 1,1,1,1,1,1
3302 // 1,1,1,1,1,1
3303 // 1,1,1,1,1,1
3304 // 1,1,1,1,1,1
3305 // 1,1,1,1,1,1
3306 // 1,1,1,1,1,1
3307
3308 // Second Pass
3309 // ResultArr2:
3310 // 1,,1,,1,,1,,1,,1,
3311 // ,,,,,,,,,,
3312 // 1,,1,,1,,1,,1,,1,
3313 // ,,,,,,,,,,
3314 // 1,,1,,1,,1,,1,,1,
3315 // ,,,,,,,,,,
3316 // 1,,1,,1,,1,,1,,1,
3317 // ,,,,,,,,,,
3318 // 1,,1,,1,,1,,1,,1,
3319 // ,,,,,,,,,,
3320 // 1,,1,,1,,1,,1,,1,
3321
3322 // Third pass fills in the blanks
3323 // ResultArr2:
3324 // 1,1,1,1,1,1,1,1,1,1,1,1
3325 // 1,1,1,1,1,1,1,1,1,1,1,1
3326 // 1,1,1,1,1,1,1,1,1,1,1,1
3327 // 1,1,1,1,1,1,1,1,1,1,1,1
3328 // 1,1,1,1,1,1,1,1,1,1,1,1
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
3336 // X,Y = .
3337 // X+1,y = ^
3338 // X,Y+1 = *
3339 // X+1,Y+1 = #
3340
3341 // Filling in like this;
3342 // .*
3343 // ^#
3344 // 1st .
3345 // 2nd *
3346 // 3rd ^
3347 // 4th #
3348 // on single loop.
3349
3350 float[,] resultarr2 = new float[512,512];
3351 for (int y = 0; y < (int)Constants.RegionSize; y++)
3352 {
3353 for (int x = 0; x < (int)Constants.RegionSize; x++)
3354 {
3355 resultarr2[y*2, x*2] = resultarr[y, x];
3356
3357 if (y < (int)Constants.RegionSize)
3358 {
3359 if (y + 1 < (int)Constants.RegionSize)
3360 {
3361 if (x + 1 < (int)Constants.RegionSize)
3362 {
3363 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3364 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3365 }
3366 else
3367 {
3368 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3369 }
3370 }
3371 else
3372 {
3373 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3374 }
3375 }
3376 if (x < (int)Constants.RegionSize)
3377 {
3378 if (x + 1 < (int)Constants.RegionSize)
3379 {
3380 if (y + 1 < (int)Constants.RegionSize)
3381 {
3382 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3383 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3384 }
3385 else
3386 {
3387 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3388 }
3389 }
3390 else
3391 {
3392 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3393 }
3394 }
3395 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3396 {
3397 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3398 {
3399 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3400 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3401 }
3402 else
3403 {
3404 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3405 }
3406 }
3407 }
3408 }
3409 //Flatten out the array
3410 int i = 0;
3411 for (int y = 0; y < 512; y++)
3412 {
3413 for (int x = 0; x < 512; x++)
3414 {
3415 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3416 {
3417 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3418 resultarr2[y, x] = 0;
3419 }
3420 returnarr[i] = resultarr2[y, x];
3421 i++;
3422 }
3423 }
3424
3425 return returnarr;
3426 }
3427
3428 #endregion
3429
3430 public override void SetTerrain(float[] heightMap)
3431 {
3432 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3433 {
3434 if (m_parentScene is OdeScene)
3435 {
3436 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3437 }
3438 }
3439 else
3440 {
3441 SetTerrain(heightMap, m_worldOffset);
3442 }
3443 }
3444
3445 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3446 {
3447 // this._heightmap[i] = (double)heightMap[i];
3448 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3449 //_origheightmap = heightMap;
3450
3451 float[] _heightmap;
3452
3453 // zero out a heightmap array float array (single dimension [flattened]))
3454 //if ((int)Constants.RegionSize == 256)
3455 // _heightmap = new float[514 * 514];
3456 //else
3457
3458 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3459
3460 uint heightmapWidth = Constants.RegionSize + 1;
3461 uint heightmapHeight = Constants.RegionSize + 1;
3462
3463 uint heightmapWidthSamples;
3464
3465 uint heightmapHeightSamples;
3466
3467 //if (((int)Constants.RegionSize) == 256)
3468 //{
3469 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3470 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3471 // heightmapWidth++;
3472 // heightmapHeight++;
3473 //}
3474 //else
3475 //{
3476
3477 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3478 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3479 //}
3480
3481 const float scale = 1.0f;
3482 const float offset = 0.0f;
3483 const float thickness = 0.2f;
3484 const int wrap = 0;
3485
3486 int regionsize = (int) Constants.RegionSize + 2;
3487 //Double resolution
3488 //if (((int)Constants.RegionSize) == 256)
3489 // heightMap = ResizeTerrain512Interpolation(heightMap);
3490
3491
3492 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3493 // regionsize = 512;
3494
3495 float hfmin = 2000;
3496 float hfmax = -2000;
3497
3498 for (int x = 0; x < heightmapWidthSamples; x++)
3499 {
3500 for (int y = 0; y < heightmapHeightSamples; y++)
3501 {
3502 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3503 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3504
3505
3506 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3507 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3508
3509 hfmin = (val < hfmin) ? val : hfmin;
3510 hfmax = (val > hfmax) ? val : hfmax;
3511 }
3512 }
3513
3514
3515
3516
3517 lock (OdeLock)
3518 {
3519 IntPtr GroundGeom = IntPtr.Zero;
3520 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3521 {
3522 RegionTerrain.Remove(pOffset);
3523 if (GroundGeom != IntPtr.Zero)
3524 {
3525 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3526 {
3527 TerrainHeightFieldHeights.Remove(GroundGeom);
3528 }
3529 d.SpaceRemove(space, GroundGeom);
3530 d.GeomDestroy(GroundGeom);
3531 }
3532
3533 }
3534 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3535 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3536 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3537 offset, thickness, wrap);
3538 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3539 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3540 if (GroundGeom != IntPtr.Zero)
3541 {
3542 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3543 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3544
3545 }
3546 geom_name_map[GroundGeom] = "Terrain";
3547
3548 d.Matrix3 R = new d.Matrix3();
3549
3550 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3551 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3552 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3553
3554 q1 = q1 * q2;
3555 //q1 = q1 * q3;
3556 Vector3 v3;
3557 float angle;
3558 q1.GetAxisAngle(out v3, out angle);
3559
3560 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3561 d.GeomSetRotation(GroundGeom, ref R);
3562 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)) - 1, (pOffset.Y + ((int)Constants.RegionSize * 0.5f)) - 1, 0);
3563 IntPtr testGround = IntPtr.Zero;
3564 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3565 {
3566 RegionTerrain.Remove(pOffset);
3567 }
3568 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3569 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3570
3571 }
3572 }
3573
3574 public override void DeleteTerrain()
3575 {
3576 }
3577
3578 public float GetWaterLevel()
3579 {
3580 return waterlevel;
3581 }
3582
3583 public override bool SupportsCombining()
3584 {
3585 return true;
3586 }
3587
3588 public override void UnCombine(PhysicsScene pScene)
3589 {
3590 IntPtr localGround = IntPtr.Zero;
3591// float[] localHeightfield;
3592 bool proceed = false;
3593 List<IntPtr> geomDestroyList = new List<IntPtr>();
3594
3595 lock (OdeLock)
3596 {
3597 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3598 {
3599 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3600 {
3601 if (geom == localGround)
3602 {
3603// localHeightfield = TerrainHeightFieldHeights[geom];
3604 proceed = true;
3605 }
3606 else
3607 {
3608 geomDestroyList.Add(geom);
3609 }
3610 }
3611
3612 if (proceed)
3613 {
3614 m_worldOffset = Vector3.Zero;
3615 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3616 m_parentScene = null;
3617
3618 foreach (IntPtr g in geomDestroyList)
3619 {
3620 // removingHeightField needs to be done or the garbage collector will
3621 // collect the terrain data before we tell ODE to destroy it causing
3622 // memory corruption
3623 if (TerrainHeightFieldHeights.ContainsKey(g))
3624 {
3625// float[] removingHeightField = TerrainHeightFieldHeights[g];
3626 TerrainHeightFieldHeights.Remove(g);
3627
3628 if (RegionTerrain.ContainsKey(g))
3629 {
3630 RegionTerrain.Remove(g);
3631 }
3632
3633 d.GeomDestroy(g);
3634 //removingHeightField = new float[0];
3635 }
3636 }
3637
3638 }
3639 else
3640 {
3641 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3642
3643 }
3644 }
3645 }
3646 }
3647
3648 public override void SetWaterLevel(float baseheight)
3649 {
3650 waterlevel = baseheight;
3651 randomizeWater(waterlevel);
3652 }
3653
3654 public void randomizeWater(float baseheight)
3655 {
3656 const uint heightmapWidth = m_regionWidth + 2;
3657 const uint heightmapHeight = m_regionHeight + 2;
3658 const uint heightmapWidthSamples = m_regionWidth + 2;
3659 const uint heightmapHeightSamples = m_regionHeight + 2;
3660 const float scale = 1.0f;
3661 const float offset = 0.0f;
3662 const float thickness = 2.9f;
3663 const int wrap = 0;
3664
3665 for (int i = 0; i < (258 * 258); i++)
3666 {
3667 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3668 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3669 }
3670
3671 lock (OdeLock)
3672 {
3673 if (WaterGeom != IntPtr.Zero)
3674 {
3675 d.SpaceRemove(space, WaterGeom);
3676 }
3677 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3678 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3679 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3680 offset, thickness, wrap);
3681 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3682 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3683 if (WaterGeom != IntPtr.Zero)
3684 {
3685 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3686 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3687
3688 }
3689 geom_name_map[WaterGeom] = "Water";
3690
3691 d.Matrix3 R = new d.Matrix3();
3692
3693 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3694 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3695 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3696
3697 q1 = q1 * q2;
3698 //q1 = q1 * q3;
3699 Vector3 v3;
3700 float angle;
3701 q1.GetAxisAngle(out v3, out angle);
3702
3703 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3704 d.GeomSetRotation(WaterGeom, ref R);
3705 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3706
3707 }
3708
3709 }
3710
3711 public override void Dispose()
3712 {
3713 m_rayCastManager.Dispose();
3714 m_rayCastManager = null;
3715
3716 lock (OdeLock)
3717 {
3718 lock (_prims)
3719 {
3720 foreach (OdePrim prm in _prims)
3721 {
3722 RemovePrim(prm);
3723 }
3724 }
3725
3726 //foreach (OdeCharacter act in _characters)
3727 //{
3728 //RemoveAvatar(act);
3729 //}
3730 d.WorldDestroy(world);
3731 //d.CloseODE();
3732 }
3733 }
3734 public override Dictionary<uint, float> GetTopColliders()
3735 {
3736 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3737 int cnt = 0;
3738 lock (_prims)
3739 {
3740 foreach (OdePrim prm in _prims)
3741 {
3742 if (prm.CollisionScore > 0)
3743 {
3744 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3745 cnt++;
3746 prm.CollisionScore = 0f;
3747 if (cnt > 25)
3748 {
3749 break;
3750 }
3751 }
3752 }
3753 }
3754 return returncolliders;
3755 }
3756
3757 public override bool SupportsRayCast()
3758 {
3759 return true;
3760 }
3761
3762 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3763 {
3764 if (retMethod != null)
3765 {
3766 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3767 }
3768 }
3769
3770#if USE_DRAWSTUFF
3771 // Keyboard callback
3772 public void command(int cmd)
3773 {
3774 IntPtr geom;
3775 d.Mass mass;
3776 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3777
3778
3779
3780 Char ch = Char.ToLower((Char)cmd);
3781 switch ((Char)ch)
3782 {
3783 case 'w':
3784 try
3785 {
3786 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));
3787
3788 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3789 ds.SetViewpoint(ref xyz, ref hpr);
3790 }
3791 catch (ArgumentException)
3792 { hpr.X = 0; }
3793 break;
3794
3795 case 'a':
3796 hpr.X++;
3797 ds.SetViewpoint(ref xyz, ref hpr);
3798 break;
3799
3800 case 's':
3801 try
3802 {
3803 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));
3804
3805 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3806 ds.SetViewpoint(ref xyz, ref hpr);
3807 }
3808 catch (ArgumentException)
3809 { hpr.X = 0; }
3810 break;
3811 case 'd':
3812 hpr.X--;
3813 ds.SetViewpoint(ref xyz, ref hpr);
3814 break;
3815 case 'r':
3816 xyz.Z++;
3817 ds.SetViewpoint(ref xyz, ref hpr);
3818 break;
3819 case 'f':
3820 xyz.Z--;
3821 ds.SetViewpoint(ref xyz, ref hpr);
3822 break;
3823 case 'e':
3824 xyz.Y++;
3825 ds.SetViewpoint(ref xyz, ref hpr);
3826 break;
3827 case 'q':
3828 xyz.Y--;
3829 ds.SetViewpoint(ref xyz, ref hpr);
3830 break;
3831 }
3832 }
3833
3834 public void step(int pause)
3835 {
3836
3837 ds.SetColor(1.0f, 1.0f, 0.0f);
3838 ds.SetTexture(ds.Texture.Wood);
3839 lock (_prims)
3840 {
3841 foreach (OdePrim prm in _prims)
3842 {
3843 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3844 if (prm.prim_geom != IntPtr.Zero)
3845 {
3846 d.Vector3 pos;
3847 d.GeomCopyPosition(prm.prim_geom, out pos);
3848 //d.BodyCopyPosition(body, out pos);
3849
3850 d.Matrix3 R;
3851 d.GeomCopyRotation(prm.prim_geom, out R);
3852 //d.BodyCopyRotation(body, out R);
3853
3854
3855 d.Vector3 sides = new d.Vector3();
3856 sides.X = prm.Size.X;
3857 sides.Y = prm.Size.Y;
3858 sides.Z = prm.Size.Z;
3859
3860 ds.DrawBox(ref pos, ref R, ref sides);
3861 }
3862 }
3863 }
3864 ds.SetColor(1.0f, 0.0f, 0.0f);
3865 lock (_characters)
3866 {
3867 foreach (OdeCharacter chr in _characters)
3868 {
3869 if (chr.Shell != IntPtr.Zero)
3870 {
3871 IntPtr body = d.GeomGetBody(chr.Shell);
3872
3873 d.Vector3 pos;
3874 d.GeomCopyPosition(chr.Shell, out pos);
3875 //d.BodyCopyPosition(body, out pos);
3876
3877 d.Matrix3 R;
3878 d.GeomCopyRotation(chr.Shell, out R);
3879 //d.BodyCopyRotation(body, out R);
3880
3881 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3882 d.Vector3 sides = new d.Vector3();
3883 sides.X = 0.5f;
3884 sides.Y = 0.5f;
3885 sides.Z = 0.5f;
3886
3887 ds.DrawBox(ref pos, ref R, ref sides);
3888 }
3889 }
3890 }
3891 }
3892
3893 public void start(int unused)
3894 {
3895 ds.SetViewpoint(ref xyz, ref hpr);
3896 }
3897#endif
3898 }
3899}