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